proxy.c 49.9 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
linphone
Copyright (C) 2000  Simon MORLAT (simon.morlat@linphone.org)
*/
/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
20

21 22 23 24
#include "linphone/core.h"
#include "linphone/core_utils.h"
#include "linphone/sipsetup.h"
#include "linphone/lpconfig.h"
aymeric's avatar
aymeric committed
25
#include "private.h"
26
#include "mediastreamer2/mediastream.h"
27
#include "enum.h"
28 29
#include <ctype.h>

30
/*store current config related to server location*/
31
static void linphone_proxy_config_store_server_config(LinphoneProxyConfig* cfg) {
Simon Morlat's avatar
Simon Morlat committed
32
	if (cfg->saved_identity) linphone_address_unref(cfg->saved_identity);
33 34
	if (cfg->identity_address)
		cfg->saved_identity = linphone_address_clone(cfg->identity_address);
35
	else
36
		cfg->saved_identity = NULL;
37

Simon Morlat's avatar
Simon Morlat committed
38
	if (cfg->saved_proxy) linphone_address_unref(cfg->saved_proxy);
39 40
	if (cfg->reg_proxy)
		cfg->saved_proxy = linphone_address_new(cfg->reg_proxy);
41
	else
42
		cfg->saved_proxy = NULL;
43 44
}

45
LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b) {
46
	if (a == NULL && b == NULL)
47
		return LinphoneProxyConfigAddressEqual;
48
	else if (!a || !b)
49
		return LinphoneProxyConfigAddressDifferent;
50

51 52
	if (linphone_address_equal(a,b))
		return LinphoneProxyConfigAddressEqual;
53 54
	if (linphone_address_weak_equal(a,b)) {
		/*also check both transport and uri */
Simon Morlat's avatar
Simon Morlat committed
55
		if (linphone_address_get_secure(a) == linphone_address_get_secure(b) && linphone_address_get_transport(a) == linphone_address_get_transport(b))
56 57 58 59 60
			return LinphoneProxyConfigAddressWeakEqual;
		else
			return LinphoneProxyConfigAddressDifferent;
	}
	return LinphoneProxyConfigAddressDifferent; /*either username, domain or port ar not equals*/
61 62
}

63 64
LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* cfg) {
	LinphoneAddress *current_proxy=cfg->reg_proxy?linphone_address_new(cfg->reg_proxy):NULL;
65 66
	LinphoneProxyConfigAddressComparisonResult result_identity;
	LinphoneProxyConfigAddressComparisonResult result;
67
	
68
	result = linphone_proxy_config_address_equal(cfg->saved_identity,cfg->identity_address);
69
	if (result == LinphoneProxyConfigAddressDifferent) goto end;
70
	result_identity = result;
71

72
	result = linphone_proxy_config_address_equal(cfg->saved_proxy,current_proxy);
73
	if (result == LinphoneProxyConfigAddressDifferent) goto end;
74 75 76 77 78
	/** If the proxies are equal use the result of the difference between the identities,
	  * otherwise the result is weak-equal and so weak-equal must be returned even if the
	  * identities were equal.
	  */
	if (result == LinphoneProxyConfigAddressEqual) result = result_identity;
79

Simon Morlat's avatar
Simon Morlat committed
80
	end:
Simon Morlat's avatar
Simon Morlat committed
81
	if (current_proxy) linphone_address_unref(current_proxy);
82
	ms_message("linphone_proxy_config_is_server_config_changed : %i", result);
Simon Morlat's avatar
Simon Morlat committed
83
	return result;
84
}
85

smorlat's avatar
smorlat committed
86
void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){
87
	bctbx_list_t *elem;
smorlat's avatar
smorlat committed
88
	int i;
89
	if (!linphone_core_ready(lc)) return;
90

91
	for(elem=lc->sip_conf.proxies,i=0;elem!=NULL;elem=bctbx_list_next(elem),i++){
smorlat's avatar
smorlat committed
92 93 94
		LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
		linphone_proxy_config_write_to_config_file(lc->config,cfg,i);
	}
95 96
	/*to ensure removed configs are erased:*/
	linphone_proxy_config_write_to_config_file(lc->config,NULL,i);
97
	lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy_config_index(lc));
smorlat's avatar
smorlat committed
98
}
aymeric's avatar
aymeric committed
99

100
static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *cfg) {
101 102 103 104
	const char *dial_prefix = lc ? lp_config_get_default_string(lc->config,"proxy","dial_prefix",NULL) : NULL;
	const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL;
	const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL;
	const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL;
105
	const char *realm = lc ? lp_config_get_default_string(lc->config, "proxy", "realm", NULL) : NULL;
106
	const char *quality_reporting_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "quality_reporting_collector", NULL) : NULL;
107 108
	const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL;
	const char *contact_uri_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_uri_parameters", NULL) : NULL;
109
	const char *refkey = lc ? lp_config_get_default_string(lc->config, "proxy", "refkey", NULL) : NULL;
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
	cfg->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600;
	cfg->reg_sendregister = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 1) : 1;
	cfg->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL;
	cfg->dial_escape_plus = lc ? lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0;
	cfg->privacy = lc ? lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault;
	cfg->identity_address = identity ? linphone_address_new(identity) : NULL;
	cfg->reg_identity = cfg->identity_address ? linphone_address_as_string(cfg->identity_address) : NULL;
	cfg->reg_proxy = proxy ? ms_strdup(proxy) : NULL;
	cfg->reg_route = route ? ms_strdup(route) : NULL;
	cfg->realm = realm ? ms_strdup(realm) : NULL;
	cfg->quality_reporting_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0;
	cfg->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL;
	cfg->quality_reporting_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_interval", 0) : 0;
	cfg->contact_params = contact_params ? ms_strdup(contact_params) : NULL;
	cfg->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL;
	cfg->avpf_mode = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf", LinphoneAVPFDefault) : LinphoneAVPFDefault;
	cfg->avpf_rr_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf_rr_interval", 5) : 5;
127
	cfg->publish_expires= lc ? lp_config_get_default_int(lc->config, "proxy", "publish_expires", -1) : -1;
128
	cfg->refkey = refkey ? ms_strdup(refkey) : NULL;
aymeric's avatar
aymeric committed
129 130
}

131 132 133
LinphoneProxyConfig *linphone_proxy_config_new() {
	return linphone_core_create_proxy_config(NULL);
}
134

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
static char * append_linphone_address(LinphoneAddress *addr,char *out) {
	char *res = out;
	if (addr) {
		char *tmp;
		tmp = linphone_address_as_string(addr);
		res = ms_strcat_printf(out, "%s",tmp);
		ms_free(tmp);
	}
	return res;
};
static char * append_string(const char * string,char *out) {
	char *res = out;
	if (string) {
		res = ms_strcat_printf(out, "%s",string);
	}
	return res;
}
/*
 * return true if computed value has changed
 */
bool_t linphone_proxy_config_compute_publish_params_hash(LinphoneProxyConfig * cfg) {
	char * source = NULL;
	char hash[33];
	char saved;
	unsigned long long previous_hash[2];
	previous_hash[0] = cfg->previous_publish_config_hash[0];
	previous_hash[1] = cfg->previous_publish_config_hash[1];
162

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
	source = ms_strcat_printf(source, "%i",cfg->privacy);
	source=append_linphone_address(cfg->identity_address, source);
	source=append_string(cfg->reg_proxy,source);
	source=append_string(cfg->reg_route,source);
	source=append_string(cfg->realm,source);
	source = ms_strcat_printf(source, "%i",cfg->publish_expires);
	source = ms_strcat_printf(source, "%i",cfg->publish);
	belle_sip_auth_helper_compute_ha1(source, "dummy", "dummy", hash);
	ms_free(source);
	saved = hash[16];
	hash[16] = '\0';
	cfg->previous_publish_config_hash[0] = strtoull(hash, (char **)NULL, 16);
	hash[16] = saved;
	cfg->previous_publish_config_hash[1] = strtoull(&hash[16], (char **)NULL, 16);
	return previous_hash[0] != cfg->previous_publish_config_hash[0] || previous_hash[1] != cfg->previous_publish_config_hash[1];
}
179
static void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg);
180 181 182 183 184 185 186 187 188 189

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneProxyConfig);

BELLE_SIP_INSTANCIATE_VPTR(LinphoneProxyConfig, belle_sip_object_t,
	(belle_sip_object_destroy_t)_linphone_proxy_config_destroy,
	NULL, // clone
	NULL, // marshal
	FALSE
);

190
LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) {
191 192 193
	LinphoneProxyConfig *cfg = belle_sip_object_new(LinphoneProxyConfig);
	linphone_proxy_config_init(lc,cfg);
	return cfg;
194 195
}

196 197 198 199 200
void _linphone_proxy_config_release_ops(LinphoneProxyConfig *cfg){
	if (cfg->op) {
		sal_op_release(cfg->op);
		cfg->op=NULL;
	}
201
	if (cfg->long_term_event){
202
		linphone_event_terminate(cfg->long_term_event);
203 204
		linphone_event_unref(cfg->long_term_event);
		cfg->long_term_event=NULL;
205 206 207 208 209 210
	}
}

void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg){
	if (cfg->reg_proxy!=NULL) ms_free(cfg->reg_proxy);
	if (cfg->reg_identity!=NULL) ms_free(cfg->reg_identity);
Simon Morlat's avatar
Simon Morlat committed
211
	if (cfg->identity_address!=NULL) linphone_address_unref(cfg->identity_address);
212 213 214 215 216 217 218 219
	if (cfg->reg_route!=NULL) ms_free(cfg->reg_route);
	if (cfg->quality_reporting_collector!=NULL) ms_free(cfg->quality_reporting_collector);
	if (cfg->ssctx!=NULL) sip_setup_context_free(cfg->ssctx);
	if (cfg->realm!=NULL) ms_free(cfg->realm);
	if (cfg->type!=NULL) ms_free(cfg->type);
	if (cfg->dial_prefix!=NULL) ms_free(cfg->dial_prefix);
	if (cfg->contact_params) ms_free(cfg->contact_params);
	if (cfg->contact_uri_params) ms_free(cfg->contact_uri_params);
Simon Morlat's avatar
Simon Morlat committed
220 221
	if (cfg->saved_proxy!=NULL) linphone_address_unref(cfg->saved_proxy);
	if (cfg->saved_identity!=NULL) linphone_address_unref(cfg->saved_identity);
222
	if (cfg->sent_headers!=NULL) sal_custom_header_free(cfg->sent_headers);
223
	if (cfg->pending_contact) linphone_address_unref(cfg->pending_contact);
224
	if (cfg->refkey) ms_free(cfg->refkey);
Ghislain MARY's avatar
Ghislain MARY committed
225 226 227
	if (cfg->nat_policy != NULL) {
		linphone_nat_policy_unref(cfg->nat_policy);
	}
228
	_linphone_proxy_config_release_ops(cfg);
229 230 231 232 233 234
}

void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg) {
	belle_sip_object_unref(cfg);
}

235 236 237 238 239
void _linphone_proxy_config_release(LinphoneProxyConfig *cfg) {
	_linphone_proxy_config_release_ops(cfg);
	belle_sip_object_unref(cfg);
}

240 241 242 243 244 245 246
LinphoneProxyConfig *linphone_proxy_config_ref(LinphoneProxyConfig *cfg) {
	belle_sip_object_ref(cfg);
	return cfg;
}

void linphone_proxy_config_unref(LinphoneProxyConfig *cfg) {
	belle_sip_object_unref(cfg);
aymeric's avatar
aymeric committed
247 248
}

249 250
bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *cfg){
	return cfg->state == LinphoneRegistrationOk;
smorlat's avatar
smorlat committed
251 252
}

253
int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *cfg, const char *server_addr){
254 255
	LinphoneAddress *addr=NULL;
	char *modified=NULL;
256

257 258
	if (cfg->reg_proxy!=NULL) ms_free(cfg->reg_proxy);
	cfg->reg_proxy=NULL;
259

aymeric's avatar
aymeric committed
260
	if (server_addr!=NULL && strlen(server_addr)>0){
261
		if (strstr(server_addr,"sip:")==NULL && strstr(server_addr,"sips:")==NULL){
262 263 264
			modified=ms_strdup_printf("sip:%s",server_addr);
			addr=linphone_address_new(modified);
			ms_free(modified);
265
		}
266 267
		if (addr==NULL)
			addr=linphone_address_new(server_addr);
268
		if (addr){
269
			cfg->reg_proxy=linphone_address_as_string(addr);
Simon Morlat's avatar
Simon Morlat committed
270
			linphone_address_unref(addr);
aymeric's avatar
aymeric committed
271 272
		}else{
			ms_warning("Could not parse %s",server_addr);
273
			return -1;
aymeric's avatar
aymeric committed
274 275 276 277 278
		}
	}
	return 0;
}

279 280 281

int linphone_proxy_config_set_identity_address(LinphoneProxyConfig *cfg, const LinphoneAddress *addr){
	if (!addr || linphone_address_get_username(addr)==NULL){
282 283
		char* as_string = addr ? linphone_address_as_string(addr) : ms_strdup("NULL");
		ms_warning("Invalid sip identity: %s", as_string);
284 285 286 287
		ms_free(as_string);
		return -1;
	}
	if (cfg->identity_address != NULL) {
Simon Morlat's avatar
Simon Morlat committed
288
		linphone_address_unref(cfg->identity_address);
289 290 291 292 293 294 295 296 297 298 299
	}
	cfg->identity_address=linphone_address_clone(addr);

	if (cfg->reg_identity!=NULL) {
		ms_free(cfg->reg_identity);
	}
	cfg->reg_identity= linphone_address_as_string(cfg->identity_address);
	return 0;
}

int linphone_proxy_config_set_identity(LinphoneProxyConfig *cfg, const char *identity){
aymeric's avatar
aymeric committed
300
	if (identity!=NULL && strlen(identity)>0){
301 302
		LinphoneAddress *addr=linphone_address_new(identity);
		int ret=linphone_proxy_config_set_identity_address(cfg, addr);
Simon Morlat's avatar
Simon Morlat committed
303
		if (addr) linphone_address_unref(addr);
304
		return ret;
aymeric's avatar
aymeric committed
305
	}
306
	return -1;
smorlat's avatar
smorlat committed
307 308 309
}

const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){
310
	return cfg->identity_address ? linphone_address_get_domain(cfg->identity_address) : NULL;
aymeric's avatar
aymeric committed
311 312
}

313
int linphone_proxy_config_set_route(LinphoneProxyConfig *cfg, const char *route)
aymeric's avatar
aymeric committed
314
{
315 316 317
	if (cfg->reg_route!=NULL){
		ms_free(cfg->reg_route);
		cfg->reg_route=NULL;
aymeric's avatar
aymeric committed
318
	}
319
	if (route!=NULL && route[0] !='\0'){
320 321
		SalAddress *addr;
		char *tmp;
322
		/*try to prepend 'sip:' */
323
		if (strstr(route,"sip:")==NULL && strstr(route,"sips:")==NULL){
324 325 326 327 328
			tmp=ms_strdup_printf("sip:%s",route);
		}else tmp=ms_strdup(route);
		addr=sal_address_new(tmp);
		if (addr!=NULL){
			sal_address_destroy(addr);
329 330
			cfg->reg_route=tmp;
			return 0;
331 332
		}else{
			ms_free(tmp);
333
			return -1;
334
		}
335 336
	} else {
		return 0;
337
	}
aymeric's avatar
aymeric committed
338 339
}

340 341
bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *cfg){
	if (cfg->reg_proxy==NULL){
342 343
		if (lc)
			linphone_core_notify_display_warning(lc,_("The sip proxy address you entered is invalid, it must start with \"sip:\""
aymeric's avatar
aymeric committed
344 345 346
						" followed by a hostname."));
		return FALSE;
	}
347
	if (cfg->identity_address==NULL){
348 349
		if (lc)
			linphone_core_notify_display_warning(lc,_("The sip identity you entered is invalid.\nIt should look like "
aymeric's avatar
aymeric committed
350 351 352 353 354 355
					"sip:username@proxydomain, such as sip:alice@example.net"));
		return FALSE;
	}
	return TRUE;
}

356
void linphone_proxy_config_enableregister(LinphoneProxyConfig *cfg, bool_t val){
357
	if (val != cfg->reg_sendregister) cfg->register_changed = TRUE;
358
	cfg->reg_sendregister=val;
aymeric's avatar
aymeric committed
359 360
}

361
void linphone_proxy_config_set_expires(LinphoneProxyConfig *cfg, int val){
362
	if (val<0) val=600;
363
	if (val != cfg->expires) cfg->register_changed = TRUE;
364
	cfg->expires=val;
aymeric's avatar
aymeric committed
365 366
}

367 368
void linphone_proxy_config_enable_publish(LinphoneProxyConfig *cfg, bool_t val){
	cfg->publish=val;
aymeric's avatar
aymeric committed
369
}
370

371 372
void linphone_proxy_config_pause_register(LinphoneProxyConfig *cfg){
	if (cfg->op) sal_op_stop_refreshing(cfg->op);
373 374
}

375
void linphone_proxy_config_edit(LinphoneProxyConfig *cfg){
376
	/*store current config related to server location*/
377
	linphone_proxy_config_store_server_config(cfg);
378
	linphone_proxy_config_compute_publish_params_hash(cfg);
379

380 381 382
	if (cfg->publish && cfg->long_term_event){
		linphone_event_pause_publish(cfg->long_term_event);
	}
383
	/*Don't stop refresher*/
aymeric's avatar
aymeric committed
384 385
}

386 387 388
void linphone_proxy_config_apply(LinphoneProxyConfig *cfg,LinphoneCore *lc){
	cfg->lc=lc;
	linphone_proxy_config_done(cfg);
aymeric's avatar
aymeric committed
389
}
Simon Morlat's avatar
Simon Morlat committed
390

391 392 393 394 395 396 397 398 399 400 401 402 403
void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig * cfg){
	LinphoneAddress *contact_addr=NULL;
	if (	cfg->op
			&& cfg->state == LinphoneRegistrationOk
			&& (contact_addr = (LinphoneAddress*)sal_op_get_contact_address(cfg->op))
			&& linphone_address_get_transport(contact_addr) != LinphoneTransportUdp /*with udp, there is a risk of port reuse, so I prefer to not do anything for now*/) {
		/*need to save current contact in order to reset is later*/
		linphone_address_ref(contact_addr);
		if (cfg->pending_contact)
			linphone_address_unref(cfg->pending_contact);
		cfg->pending_contact=contact_addr;

	}
404 405 406 407
	if (cfg->long_term_event){ /*might probably do better*/
		linphone_event_terminate(cfg->long_term_event);
		linphone_event_unref(cfg->long_term_event);
		cfg->long_term_event=NULL;
408
	}
409 410 411
	if (cfg->op){
		sal_op_release(cfg->op);
		cfg->op=NULL;
412 413 414
	}
}

415
LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *cfg){
416
	LinphoneAddress *ret=NULL;
417
	LinphoneAddress *proxy=linphone_address_new(cfg->reg_proxy);
418
	const char *host;
419

420
	if (proxy==NULL) return NULL;
421
	host=linphone_address_get_domain(proxy);
422
	if (host!=NULL){
423 424
		int localport = -1;
		const char *localip = NULL;
425
		LinphoneAddress *contact=linphone_address_clone(cfg->identity_address);
426

427
		linphone_address_clean(contact);
428

429
		if (cfg->contact_params) {
430
			// We want to add a list of contacts params to the linphone address
431
			sal_address_set_params(contact,cfg->contact_params);
432
		}
433 434
		if (cfg->contact_uri_params){
			sal_address_set_uri_params(contact,cfg->contact_uri_params);
435
		}
436
#ifdef BUILD_UPNP
437 438 439 440
		if (cfg->lc->upnp != NULL && linphone_core_get_firewall_policy(cfg->lc)==LinphonePolicyUseUpnp &&
			linphone_upnp_context_get_state(cfg->lc->upnp) == LinphoneUpnpStateOk) {
			localip = linphone_upnp_context_get_external_ipaddress(cfg->lc->upnp);
			localport = linphone_upnp_context_get_external_port(cfg->lc->upnp);
441
		}
442
#endif //BUILD_UPNP
443
		linphone_address_set_port(contact,localport);
444 445 446 447
		linphone_address_set_domain(contact,localip);
		linphone_address_set_display_name(contact,NULL);

		ret=contact;
448
	}
Simon Morlat's avatar
Simon Morlat committed
449
	linphone_address_unref(proxy);
450 451
	return ret;
}
452

453 454 455 456
void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) {
	if (obj->op && (obj->state == LinphoneRegistrationOk ||
					(obj->state == LinphoneRegistrationProgress && obj->expires != 0))) {
		sal_unregister(obj->op);
457 458
	}
}
459

460 461 462
static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){
	if (cfg->reg_sendregister){
		LinphoneAddress* proxy=linphone_address_new(cfg->reg_proxy);
Simon Morlat's avatar
Simon Morlat committed
463
		char* proxy_string;
464
		char * from = linphone_address_as_string(cfg->identity_address);
465
		LinphoneAddress *contact;
466
		ms_message("LinphoneProxyConfig [%p] about to register (LinphoneCore version: %s)",cfg,linphone_core_get_version());
467
		proxy_string=linphone_address_as_string_uri_only(proxy);
Simon Morlat's avatar
Simon Morlat committed
468
		linphone_address_unref(proxy);
469 470 471
		if (cfg->op)
			sal_op_release(cfg->op);
		cfg->op=sal_op_new(cfg->lc->sal);
472

473
		linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE);
474

475 476
		if ((contact=guess_contact_for_register(cfg))) {
			sal_op_set_contact_address(cfg->op,contact);
Simon Morlat's avatar
Simon Morlat committed
477
			linphone_address_unref(contact);
478
		}
479

480
		sal_op_set_user_pointer(cfg->op,cfg);
481

482 483 484 485 486 487

		if (sal_register(cfg->op,proxy_string, cfg->reg_identity, cfg->expires, cfg->pending_contact)==0) {
			if (cfg->pending_contact) {
				linphone_address_unref(cfg->pending_contact);
				cfg->pending_contact=NULL;
			}
488
			linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,"Registration in progress");
489
		} else {
490
			linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,"Registration failed");
491
		}
492
		ms_free(proxy_string);
493
		ms_free(from);
494
	} else {
495
		/* unregister if registered*/
496 497
		if (cfg->state == LinphoneRegistrationProgress) {
			linphone_proxy_config_set_state(cfg,LinphoneRegistrationCleared,"Registration cleared");
498
		}
499
		_linphone_proxy_config_unregister(cfg);
aymeric's avatar
aymeric committed
500
	}
smorlat's avatar
smorlat committed
501 502
}

503 504 505 506
void linphone_proxy_config_refresh_register(LinphoneProxyConfig *cfg){
	if (cfg->reg_sendregister && cfg->op && cfg->state!=LinphoneRegistrationProgress){
		if (sal_register_refresh(cfg->op,cfg->expires) == 0) {
			linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress, "Refresh registration");
507
		}
508 509 510
	}
}

511 512 513 514 515 516

void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix){
	if (cfg->dial_prefix!=NULL){
		ms_free(cfg->dial_prefix);
		cfg->dial_prefix=NULL;
	}
517
	if (prefix && prefix[0]!='\0') cfg->dial_prefix=ms_strdup(prefix);
518 519 520 521 522 523 524 525 526 527 528 529 530
}

const char *linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg){
	return cfg->dial_prefix;
}

void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val){
	cfg->dial_escape_plus=val;
}

bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg){
	return cfg->dial_escape_plus;
}
531

532 533
void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t val){
	cfg->quality_reporting_enabled = val;
534 535
}

536
bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg){
537
	return cfg->quality_reporting_enabled;
538 539
}

540
void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, int interval) {
541
	cfg->quality_reporting_interval = interval;
542 543 544 545 546 547
}

int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg) {
	return cfg->quality_reporting_interval;
}

548
void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector){
549 550
	if (collector!=NULL && strlen(collector)>0){
		LinphoneAddress *addr=linphone_address_new(collector);
551
		if (!addr){
552
			ms_error("Invalid SIP collector URI: %s. Quality reporting will be DISABLED.",collector);
553
		} else {
554
			if (cfg->quality_reporting_collector != NULL){
555
				ms_free(cfg->quality_reporting_collector);
556
			}
557
			cfg->quality_reporting_collector = ms_strdup(collector);
558 559 560
		}

		if (addr){
Simon Morlat's avatar
Simon Morlat committed
561
			linphone_address_unref(addr);
562 563 564 565
		}
	}
}

566 567
const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *cfg){
	return cfg->quality_reporting_collector;
568 569 570
}


571
bool_t linphone_proxy_config_is_phone_number(LinphoneProxyConfig *proxy, const char *username){
572
	const char *p;
573
	if (!username) return FALSE;
574
	for(p=username;*p!='\0';++p){
575
		if (isdigit(*p) ||
576 577 578 579
			*p==' ' ||
			*p=='.' ||
			*p=='-' ||
			*p==')' ||
580 581
			*p=='(' ||
			*p=='/' ||
582
			*p=='+' ||
583 584
			(unsigned char)*p==0xca || (unsigned char)*p==0xc2 || (unsigned char)*p==0xa0 // non-breakable space (iOS uses it to format contacts phone number)
			) {
585
			continue;
586
		}
587
		return FALSE;
588 589 590 591
	}
	return TRUE;
}

592
//remove anything but [0-9] and +
593 594 595 596 597
static char *flatten_number(const char *number){
	char *result=ms_malloc0(strlen(number)+1);
	char *w=result;
	const char *r;
	for(r=number;*r!='\0';++r){
598
		if (*r=='+' || isdigit(*r)){
599 600 601 602 603 604 605
			*w++=*r;
		}
	}
	*w++='\0';
	return result;
}

jehan's avatar
jehan committed
606
/*static char* replace_plus_with_icp(char *phone, const char* icp){
607
	return (icp && phone[0]=='+') ? ms_strdup_printf("%s%s", icp, phone+1) : ms_strdup(phone);
jehan's avatar
jehan committed
608
}*/
609

610
static char* replace_icp_with_plus(char *phone, const char *icp){
611 612
	return (strstr(phone, icp) == phone) ?  ms_strdup_printf("+%s", phone+strlen(icp)) : ms_strdup(phone);
}
613

614
bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len){
615 616
	char * normalized_phone = linphone_proxy_config_normalize_phone_number(proxy, username);
	const char * output = normalized_phone ? normalized_phone : username;
617
	memset(result, 0, result_len);
618 619 620
	memcpy(result, output, MIN(strlen(output) + 1, result_len));
	ms_free(normalized_phone);
	return output != username;
621 622
}

623 624 625
char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, const char *username) {
	LinphoneProxyConfig *tmpproxy = proxy ? proxy : linphone_proxy_config_new();
	char* result = NULL;
626 627 628 629
	LinphoneDialPlan dialplan = {0};
	char * nationnal_significant_number = NULL;
	int ccc = -1;
	
630 631
	if (linphone_proxy_config_is_phone_number(tmpproxy, username)){
		char * flatten=flatten_number(username);
632
		ms_debug("Flattened number is '%s' for '%s'",flatten, username);
633

634 635
		ccc = linphone_dial_plan_lookup_ccc_from_e164(flatten);
		if (ccc>-1) { /*e164 like phone number*/
636
			dialplan = *linphone_dial_plan_by_ccc_as_int(ccc);
637
			nationnal_significant_number = strstr(flatten, dialplan.ccc);
638 639 640 641 642 643 644 645 646 647 648 649 650
			if (nationnal_significant_number) {
				nationnal_significant_number +=strlen(dialplan.ccc);
			}
		} else if (flatten[0] =='+') {
			ms_message ("Unknown ccc for e164 like number [%s]", flatten);
			goto end;
		} else {
			dialplan = *linphone_dial_plan_by_ccc(tmpproxy->dial_prefix); //copy dial plan;
			if (tmpproxy->dial_prefix){
				if (strcmp(tmpproxy->dial_prefix,dialplan.ccc) != 0){
					//probably generic dialplan, preserving proxy dial prefix
					strncpy(dialplan.ccc,tmpproxy->dial_prefix,sizeof(dialplan.ccc));
				}
651
			}
652
			if (strstr(flatten,dialplan.icp)==flatten) {
653 654 655 656 657 658
				char *e164 = replace_icp_with_plus(flatten,dialplan.icp);
				result = linphone_proxy_config_normalize_phone_number(tmpproxy,e164);
				ms_free(e164);
				goto end;
			}
			nationnal_significant_number=flatten;
659
		}
jehan's avatar
jehan committed
660
		ms_debug("Using dial plan '%s'",dialplan.country);
661

662
		/*if proxy has a dial prefix, modify phonenumber accordingly*/
663
		if (dialplan.ccc[0]!='\0') {
664
			/* the number already starts with + or international prefix*/
665 666 667 668 669 670 671 672 673 674 675 676 677 678
			/*0. keep at most national number significant digits */
			char* nationnal_significant_number_start = nationnal_significant_number
														+ MAX(0, (int)strlen(nationnal_significant_number)
														- (int)dialplan.nnl);
			ms_debug("Prefix not present. Keeping at most %d digits: %s", dialplan.nnl, nationnal_significant_number_start);

			/*1. First prepend international calling prefix or +*/
			/*2. Second add prefix*/
			/*3. Finally add user digits */
			result = ms_strdup_printf("%s%s%s"
										, tmpproxy->dial_escape_plus ? dialplan.icp : "+"
										, dialplan.ccc
										, nationnal_significant_number_start);
			ms_debug("Prepended prefix resulted in %s", result);
679
		}
680 681

	end:
682 683 684 685 686 687
		if (result==NULL) {
			result = flatten;
		} else {
			ms_free(flatten);
		}
	}
688
	if (proxy==NULL) linphone_proxy_config_destroy(tmpproxy);
689 690 691 692 693 694 695
	return result;
}

static LinphoneAddress* _linphone_core_destroy_addr_if_not_sip( LinphoneAddress* addr ){
	if( linphone_address_is_sip(addr) ) {
		return addr;
	} else {
Simon Morlat's avatar
Simon Morlat committed
696
		linphone_address_unref(addr);
697 698 699 700 701 702 703 704 705 706
		return NULL;
	}
}

LinphoneAddress* linphone_proxy_config_normalize_sip_uri(LinphoneProxyConfig *proxy, const char *username) {
	enum_lookup_res_t *enumres=NULL;
	char *enum_domain=NULL;
	char *tmpurl;
	LinphoneAddress *uri;

707
	if (!username || *username=='\0') return NULL;
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739

	if (is_enum(username,&enum_domain)){
		if (proxy) {
			linphone_core_notify_display_status(proxy->lc,_("Looking for telephone number destination..."));
		}
		if (enum_lookup(enum_domain,&enumres)<0){
			if (proxy) {
				linphone_core_notify_display_status(proxy->lc,_("Could not resolve this number."));
			}
			ms_free(enum_domain);
			return NULL;
		}
		ms_free(enum_domain);
		tmpurl=enumres->sip_address[0];
		uri=linphone_address_new(tmpurl);
		enum_lookup_res_free(enumres);
		return _linphone_core_destroy_addr_if_not_sip(uri);
	}
	/* check if we have a "sip:" or a "sips:" */
	if ( (strstr(username,"sip:")==NULL) && (strstr(username,"sips:")==NULL) ){
		/* this doesn't look like a true sip uri */
		if (strchr(username,'@')!=NULL){
			/* seems like sip: is missing !*/
			tmpurl=ms_strdup_printf("sip:%s",username);
			uri=linphone_address_new(tmpurl);
			ms_free(tmpurl);
			if (uri){
				return _linphone_core_destroy_addr_if_not_sip(uri);
			}
		}

		if (proxy!=NULL){
740
			/* append the proxy domain suffix but remove any custom parameters/headers */
741
			LinphoneAddress *uri=linphone_address_clone(linphone_proxy_config_get_identity_address(proxy));
742
			linphone_address_clean(uri);
743 744
			if (uri==NULL){
				return NULL;
745 746
			} else {
				linphone_address_set_display_name(uri,NULL);
747
				linphone_address_set_username(uri,username);
748
				return _linphone_core_destroy_addr_if_not_sip(uri);
749
			}
750 751 752
		} else {
			return NULL;
		}
753 754 755 756 757 758 759 760 761
	}
	uri=linphone_address_new(username);
	if (uri!=NULL){
		return _linphone_core_destroy_addr_if_not_sip(uri);
	}

	return NULL;
}

smorlat's avatar
smorlat committed
762 763 764
/**
 * Commits modification made to the proxy configuration.
**/
765
int linphone_proxy_config_done(LinphoneProxyConfig *cfg)
smorlat's avatar
smorlat committed
766
{
767 768
	LinphoneProxyConfigAddressComparisonResult res;

769
	if (!linphone_proxy_config_check(cfg->lc,cfg))
770 771
		return -1;

772
	/*check if server address has changed*/
773
	res = linphone_proxy_config_is_server_config_changed(cfg);
774
	if (res != LinphoneProxyConfigAddressEqual) {
775
		/* server config has changed, need to unregister from previous first*/
776
		if (cfg->op) {
777
			if (res == LinphoneProxyConfigAddressDifferent) {
778
				_linphone_proxy_config_unregister(cfg);
779
			}
780 781 782
			sal_op_set_user_pointer(cfg->op,NULL); /*we don't want to receive status for this un register*/
			sal_op_unref(cfg->op); /*but we keep refresher to handle authentication if needed*/
			cfg->op=NULL;
783
		}
784 785 786 787 788
		if (cfg->long_term_event) {
			if (res == LinphoneProxyConfigAddressDifferent) {
				_linphone_proxy_config_unpublish(cfg);
			}
		}
789
		cfg->commit = TRUE;
790
	}
791
	if (cfg->register_changed){
792
		cfg->commit = TRUE;
793 794 795 796
		cfg->register_changed = FALSE;
	}
	if (cfg->commit){
		linphone_proxy_config_pause_register(cfg);
797 798
	}
	
799 800 801
	if (linphone_proxy_config_compute_publish_params_hash(cfg)) {
		ms_message("Publish params have changed on proxy config [%p]",cfg);
		if (cfg->long_term_event) {
802
			if (cfg->publish) {
803 804 805 806 807
				const char * sip_etag = linphone_event_get_custom_header(cfg->long_term_event, "SIP-ETag");
				if (sip_etag) {
					if (cfg->sip_etag) ms_free(cfg->sip_etag);
					cfg->sip_etag = ms_strdup(sip_etag);
				}
808
			}
809 810
			/*publish is terminated*/
			linphone_event_terminate(cfg->long_term_event);
811 812 813 814 815 816
			linphone_event_unref(cfg->long_term_event);
			cfg->long_term_event = NULL;
		}
		if (cfg->publish) cfg->send_publish=TRUE;
	} else {
		ms_message("Publish params have not changed on proxy config [%p]",cfg);
817
	}
818
	
819
	linphone_proxy_config_write_all_to_config_file(cfg->lc);
aymeric's avatar
aymeric committed
820 821 822
	return 0;
}

823 824 825 826
const char* linphone_proxy_config_get_realm(const LinphoneProxyConfig *cfg)
{
	return cfg?cfg->realm:NULL;
}
aymeric's avatar
aymeric committed
827 828 829 830 831
void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm)
{
	if (cfg->realm!=NULL) {
		ms_free(cfg->realm);
	}
832
	cfg->realm=ms_strdup(realm);
aymeric's avatar
aymeric committed
833 834
}

835
int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePresenceModel *presence){
836
	int err=0;
837

838
	if (proxy->state==LinphoneRegistrationOk || proxy->state==LinphoneRegistrationCleared){
839 840 841 842 843 844 845
		LinphoneContent *content;
		char *presence_body;
		if (proxy->long_term_event==NULL){
			proxy->long_term_event = linphone_core_create_publish(proxy->lc
										 , linphone_proxy_config_get_identity_address(proxy)
										 , "presence"
										 , linphone_proxy_config_get_publish_expires(proxy));
846
			linphone_event_ref(proxy->long_term_event);
847 848
		}
		proxy->long_term_event->internal = TRUE;
849

850 851 852 853
		if (linphone_presence_model_get_presentity(presence) == NULL) {
			ms_message("No presentity set for model [%p], using identity from proxy config [%p]", presence, proxy);
			linphone_presence_model_set_presentity(presence,linphone_proxy_config_get_identity_address(proxy));
		}
854

855 856 857
		if (!(presence_body = linphone_presence_model_to_xml(presence))) {
			ms_error("Cannot publish presence model [%p] for proxy config [%p] because of xml serilization error",presence,proxy);
			return -1;
858
		}
859

860 861 862 863
		content = linphone_content_new();
		linphone_content_set_buffer(content,presence_body,strlen(presence_body));
		linphone_content_set_type(content, "application");
		linphone_content_set_subtype(content,"pidf+xml");
864 865 866 867 868
		if (proxy->sip_etag) {
			linphone_event_add_custom_header(proxy->long_term_event, "SIP-If-Match", proxy->sip_etag);
			ms_free(proxy->sip_etag);
			proxy->sip_etag=NULL;
		}
869 870
		err = linphone_event_send_publish(proxy->long_term_event, content);
		linphone_content_unref(content);
Ghislain MARY's avatar
Ghislain MARY committed
871
		ms_free(presence_body);
872
	}else proxy->send_publish=TRUE; /*otherwise do not send publish if registration is in progress, this will be done later*/
873
	return err;
aymeric's avatar
aymeric committed
874 875
}

876 877 878
void _linphone_proxy_config_unpublish(LinphoneProxyConfig *obj) {
	if (obj->long_term_event
		&& (linphone_event_get_publish_state(obj->long_term_event) == LinphonePublishOk ||
Simon Morlat's avatar
Simon Morlat committed
879
					(linphone_event_get_publish_state(obj->long_term_event)  == LinphonePublishProgress && obj->publish_expires != 0))) {
880 881
		linphone_event_unpublish(obj->long_term_event);
	}
882 883 884 885
	if (obj->sip_etag) {
		ms_free(obj->sip_etag);
		obj->sip_etag=NULL;
	}
886 887
}

888 889
const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg){
	return cfg->reg_route;
890 891
}

892 893
const LinphoneAddress *linphone_proxy_config_get_identity_address(const LinphoneProxyConfig *cfg){
	return cfg->identity_address;
894 895
}

896 897
const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *cfg){
	return cfg->reg_identity;
898 899
}

900 901
bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *cfg){
	return cfg->publish;
902 903
}

904 905
const char *linphone_proxy_config_get_server_addr(const LinphoneProxyConfig *cfg){
	return cfg->reg_proxy;
906 907 908
}

/**
909
 * @return the duration of registration.
910
**/
911 912
int linphone_proxy_config_get_expires(const LinphoneProxyConfig *cfg){
	return cfg->expires;
913 914
}

915 916 917 918 919 920 921 922
bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *cfg){
	return cfg->reg_sendregister;
}

void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *cfg, const char *contact_params){
	if (cfg->contact_params) {
		ms_free(cfg->contact_params);
		cfg->contact_params=NULL;
923 924
	}
	if (contact_params){
925
		cfg->contact_params=ms_strdup(contact_params);
926
	}
927
	cfg->register_changed = TRUE;
928 929
}

930 931 932 933
void linphone_proxy_config_set_contact_uri_parameters(LinphoneProxyConfig *cfg, const char *contact_uri_params){
	if (cfg->contact_uri_params) {
		ms_free(cfg->contact_uri_params);
		cfg->contact_uri_params=NULL;
934 935
	}
	if (contact_uri_params){
936
		cfg->contact_uri_params=ms_strdup(contact_uri_params);
937
	}
938
	cfg->register_changed = TRUE;
939 940
}

941 942
const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *cfg){
	return cfg->contact_params;
943 944
}

945 946
const char *linphone_proxy_config_get_contact_uri_parameters(const LinphoneProxyConfig *cfg){
	return cfg->contact_uri_params;
947 948
}

949 950
struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *cfg){
	return cfg->lc;
951
}
smorlat's avatar
smorlat committed
952

953 954 955 956 957 958 959 960 961
const char *linphone_proxy_config_get_custom_header(LinphoneProxyConfig *cfg, const char *header_name){
	const SalCustomHeader *ch;
	if (!cfg->op) return NULL;
	ch = sal_op_get_recv_custom_header(cfg->op);
	return sal_custom_header_find(ch, header_name);
}

void linphone_proxy_config_set_custom_header(LinphoneProxyConfig *cfg, const char *header_name, const char *header_value){
	cfg->sent_headers=sal_custom_header_append(cfg->sent_headers, header_name, header_value);
962
	cfg->register_changed = TRUE;
963 964
}

aymeric's avatar
aymeric committed
965
int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
966 967 968
	if (!linphone_proxy_config_check(lc,cfg)) {
		return -1;
	}
969
	if (bctbx_list_find(lc->sip_conf.proxies,cfg)!=NULL){
970 971 972
		ms_warning("ProxyConfig already entered, ignored.");
		return 0;
	}
973
	lc->sip_conf.proxies=bctbx_list_append(lc->sip_conf.proxies,(void *)linphone_proxy_config_ref(cfg));
aymeric's avatar
aymeric committed
974 975 976 977 978
	linphone_proxy_config_apply(cfg,lc);
	return 0;
}

void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
979
	/* check this proxy config is in the list before doing more*/
980
	if (bctbx_list_find(lc->sip_conf.proxies,cfg)==NULL){
981
		ms_error("linphone_core_remove_proxy_config: LinphoneProxyConfig [%p] is not known by LinphoneCore (programming error?)",cfg);
982 983
		return;
	}
984
	lc->sip_conf.proxies=bctbx_list_remove(lc->sip_conf.proxies,cfg);
aymeric's avatar
aymeric committed
985
	/* add to the list of destroyed proxies, so that the possible unREGISTER request can succeed authentication */
986
	lc->sip_conf.deleted_proxies=bctbx_list_append(lc->sip_conf.deleted_proxies,cfg);
987 988 989 990 991

	if (lc->default_proxy==cfg){
		lc->default_proxy=NULL;
	}

992
	cfg->deletion_date=ms_time(NULL);
993
	if (cfg->state==LinphoneRegistrationOk){
994
		/* UNREGISTER */
995
		linphone_proxy_config_edit(cfg);
996 997
		linphone_proxy_config_enable_register(cfg,FALSE);
		linphone_proxy_config_done(cfg);
998
		linphone_proxy_config_update(cfg);
999 1000
	} else if (cfg->state != LinphoneRegistrationNone) {
		linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone,"Registration disabled");
1001
	}
1002
	linphone_proxy_config_write_all_to_config_file(lc);
aymeric's avatar
aymeric committed
1003
}
1004

1005
void linphone_core_clear_proxy_config(LinphoneCore *lc){
1006 1007
	bctbx_list_t* list=bctbx_list_copy(linphone_core_get_proxy_config_list((const LinphoneCore*)lc));
	bctbx_list_t* copy=list;
1008
	for(;list!=NULL;list=list->next){
1009 1010
		linphone_core_remove_proxy_config(lc,(LinphoneProxyConfig *)list->data);
	}
1011
	bctbx_list_free(copy);
1012
	linphone_proxy_config_write_all_to_config_file(lc);
1013
}
1014

1015
int linphone_core_get_default_proxy_config_index(LinphoneCore *lc) {
1016 1017
	int pos = -1;
	if (lc->default_proxy != NULL) {
1018
		pos = bctbx_list_position(lc->sip_conf.proxies, bctbx_list_find(lc->sip_conf.proxies, (void *)lc->default_proxy));
1019 1020 1021 1022 1023
	}
	return pos;
}

void linphone_core_set_default_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config){
aymeric's avatar
aymeric committed
1024 1025
	/* check if this proxy is in our list */
	if (config!=NULL){
1026
		if (bctbx_list_find(lc->sip_conf.proxies,config)==NULL){
aymeric's avatar
aymeric committed
1027 1028 1029 1030 1031 1032
			ms_warning("Bad proxy address: it is not in the list !");
			lc->default_proxy=NULL;
			return ;
		}
	}
	lc->default_proxy=config;
1033
	if (linphone_core_ready(lc))
1034
		lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy_config_index(lc));
1035
}
aymeric's avatar
aymeric committed
1036 1037 1038

void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index){
	if (index<0) linphone_core_set_default_proxy(lc,NULL);
1039
	else linphone_core_set_default_proxy(lc,bctbx_list_nth_data(lc->sip_conf.proxies,index));
aymeric's avatar
aymeric committed
1040 1041 1042 1043
}

int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config){
	if (config!=NULL) *config=lc->default_proxy;
1044 1045 1046 1047 1048
	return linphone_core_get_default_proxy_config_index(lc);
}

LinphoneProxyConfig * linphone_core_get_default_proxy_config(LinphoneCore *lc) {
	return lc->default_proxy;
aymeric's avatar
aymeric committed
1049 1050
}

1051
const bctbx_list_t *linphone_core_get_proxy_config_list(const LinphoneCore *lc){
aymeric's avatar
aymeric committed
1052 1053 1054
	return lc->sip_conf.proxies;
}

1055
void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyConfig *cfg, int index)
aymeric's avatar
aymeric committed
1056 1057 1058 1059 1060
{
	char key[50];

	sprintf(key,"proxy_%i",index);
	lp_config_clean_section(config,key);
1061
	if (cfg==NULL){
aymeric's avatar
aymeric committed
1062 1063
		return;
	}
1064 1065
	if (cfg->type!=NULL){
		lp_config_set_string(config,key,"type",cfg->type);
smorlat's avatar
smorlat committed
1066
	}
1067 1068
	if (cfg->reg_proxy!=NULL){
		lp_config_set_string(config,key,"reg_proxy",cfg->reg_proxy);
aymeric's avatar
aymeric committed
1069
	}
1070 1071
	if (cfg->reg_route!=NULL){
		lp_config_set_string(config,key,"reg_route",cfg->reg_route);
aymeric's avatar
aymeric committed
1072
	}
1073 1074
	if (cfg->reg_identity!=NULL){
		lp_config_set_string(config,key,"reg_identity",cfg->reg_identity);
aymeric's avatar
aymeric committed
1075
	}
1076 1077
	if (cfg->realm!=NULL){
		lp_config_set_string(config,key,"realm",cfg->realm);
1078
	}
1079 1080
	if (cfg->contact_params!=NULL){
		lp_config_set_string(config,key,"contact_parameters",cfg->contact_params);
Simon Morlat's avatar
Simon Morlat committed
1081
	}
1082 1083
	if (cfg->contact_uri_params!=NULL){
		lp_config_set_string(config,key,"contact_uri_parameters",cfg->contact_uri_params);
1084
	}
1085 1086
	if (cfg->quality_reporting_collector!=NULL){
		lp_config_set_string(config,key,"quality_reporting_collector",cfg->quality_reporting_collector);
1087
	}
1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
	lp_config_set_int(config,key,"quality_reporting_enabled",cfg->quality_reporting_enabled);
	lp_config_set_int(config,key,"quality_reporting_interval",cfg->quality_reporting_interval);
	lp_config_set_int(config,key,"reg_expires",cfg->expires);
	lp_config_set_int(config,key,"reg_sendregister",cfg->reg_sendregister);
	lp_config_set_int(config,key,"publish",cfg->publish);
	lp_config_set_int(config, key, "avpf", cfg->avpf_mode);
	lp_config_set_int(config, key, "avpf_rr_interval", cfg->avpf_rr_interval);
	lp_config_set_int(config,key,"dial_escape_plus",cfg->dial_escape_plus);
	lp_config_set_string(config,key,"dial_prefix",cfg->dial_prefix);
	lp_config_set_int(config,key,"privacy",cfg->privacy);
1098
	if (cfg->refkey) lp_config_set_string(config,key,"refkey",cfg->refkey);
1099
	lp_config_set_int(config, key, "publish_expires", cfg->publish_expires);
1100 1101 1102

	if (cfg->nat_policy != NULL) {
		lp_config_set_string(config, key, "nat_policy_ref", cfg->nat_policy->ref);
1103
		linphone_nat_policy_save_to_config(cfg->nat_policy);