proxy.c 50.3 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
	cfg->lc = lc;
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
	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;
128
	cfg->publish_expires= lc ? lp_config_get_default_int(lc->config, "proxy", "publish_expires", -1) : -1;
129
	cfg->refkey = refkey ? ms_strdup(refkey) : NULL;
aymeric's avatar
aymeric committed
130 131
}

132 133 134
LinphoneProxyConfig *linphone_proxy_config_new() {
	return linphone_core_create_proxy_config(NULL);
}
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 162
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];
163

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
	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];
}
180
static void _linphone_proxy_config_destroy(LinphoneProxyConfig *cfg);
181 182 183 184 185 186 187 188 189 190

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
);

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

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

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
212
	if (cfg->identity_address!=NULL) linphone_address_unref(cfg->identity_address);
213 214 215 216 217 218 219 220
	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
221 222
	if (cfg->saved_proxy!=NULL) linphone_address_unref(cfg->saved_proxy);
	if (cfg->saved_identity!=NULL) linphone_address_unref(cfg->saved_identity);
223
	if (cfg->sent_headers!=NULL) sal_custom_header_free(cfg->sent_headers);
224
	if (cfg->pending_contact) linphone_address_unref(cfg->pending_contact);
225
	if (cfg->refkey) ms_free(cfg->refkey);
Ghislain MARY's avatar
Ghislain MARY committed
226 227 228
	if (cfg->nat_policy != NULL) {
		linphone_nat_policy_unref(cfg->nat_policy);
	}
229 230 231
	if (cfg->ei){
		linphone_error_info_unref(cfg->ei);
	}
232
	_linphone_proxy_config_release_ops(cfg);
233 234 235 236 237 238
}

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

239 240 241 242 243
void _linphone_proxy_config_release(LinphoneProxyConfig *cfg) {
	_linphone_proxy_config_release_ops(cfg);
	belle_sip_object_unref(cfg);
}

244 245 246 247 248 249 250
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
251 252
}

253 254
bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *cfg){
	return cfg->state == LinphoneRegistrationOk;
smorlat's avatar
smorlat committed
255 256
}

257
LinphoneStatus linphone_proxy_config_set_server_addr(LinphoneProxyConfig *cfg, const char *server_addr){
258 259
	LinphoneAddress *addr=NULL;
	char *modified=NULL;
260

261 262
	if (cfg->reg_proxy!=NULL) ms_free(cfg->reg_proxy);
	cfg->reg_proxy=NULL;
263

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

283

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

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

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

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

344 345
bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *cfg){
	if (cfg->reg_proxy==NULL){
346 347
		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
348 349 350
						" followed by a hostname."));
		return FALSE;
	}
351
	if (cfg->identity_address==NULL){
352 353
		if (lc)
			linphone_core_notify_display_warning(lc,_("The sip identity you entered is invalid.\nIt should look like "
aymeric's avatar
aymeric committed
354 355 356 357 358 359
					"sip:username@proxydomain, such as sip:alice@example.net"));
		return FALSE;
	}
	return TRUE;
}

360
void linphone_proxy_config_enableregister(LinphoneProxyConfig *cfg, bool_t val){
361
	if (val != cfg->reg_sendregister) cfg->register_changed = TRUE;
362
	cfg->reg_sendregister=val;
aymeric's avatar
aymeric committed
363 364
}

365
void linphone_proxy_config_set_expires(LinphoneProxyConfig *cfg, int val){
366
	if (val<0) val=600;
367
	if (val != cfg->expires) cfg->register_changed = TRUE;
368
	cfg->expires=val;
aymeric's avatar
aymeric committed
369 370
}

371 372
void linphone_proxy_config_enable_publish(LinphoneProxyConfig *cfg, bool_t val){
	cfg->publish=val;
aymeric's avatar
aymeric committed
373
}
374

375 376
void linphone_proxy_config_pause_register(LinphoneProxyConfig *cfg){
	if (cfg->op) sal_op_stop_refreshing(cfg->op);
377 378
}

379
void linphone_proxy_config_edit(LinphoneProxyConfig *cfg){
380
	/*store current config related to server location*/
381
	linphone_proxy_config_store_server_config(cfg);
382
	linphone_proxy_config_compute_publish_params_hash(cfg);
383

384 385 386
	if (cfg->publish && cfg->long_term_event){
		linphone_event_pause_publish(cfg->long_term_event);
	}
387
	/*Don't stop refresher*/
aymeric's avatar
aymeric committed
388 389
}

390 391 392
void linphone_proxy_config_apply(LinphoneProxyConfig *cfg,LinphoneCore *lc){
	cfg->lc=lc;
	linphone_proxy_config_done(cfg);
aymeric's avatar
aymeric committed
393
}
Simon Morlat's avatar
Simon Morlat committed
394

395 396 397 398 399 400 401 402 403 404 405 406 407
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;

	}
408 409 410 411
	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;
412
	}
413 414 415
	if (cfg->op){
		sal_op_release(cfg->op);
		cfg->op=NULL;
416 417 418
	}
}

419
LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *cfg){
420
	LinphoneAddress *ret=NULL;
421
	LinphoneAddress *proxy=linphone_address_new(cfg->reg_proxy);
422
	const char *host;
423

424
	if (proxy==NULL) return NULL;
425
	host=linphone_address_get_domain(proxy);
426
	if (host!=NULL){
427 428
		int localport = -1;
		const char *localip = NULL;
429
		LinphoneAddress *contact=linphone_address_clone(cfg->identity_address);
430

431
		linphone_address_clean(contact);
432

433
		if (cfg->contact_params) {
434
			// We want to add a list of contacts params to the linphone address
435
			sal_address_set_params(contact,cfg->contact_params);
436
		}
437 438
		if (cfg->contact_uri_params){
			sal_address_set_uri_params(contact,cfg->contact_uri_params);
439
		}
440
#ifdef BUILD_UPNP
441 442 443 444
		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);
445
		}
446
#endif //BUILD_UPNP
447
		linphone_address_set_port(contact,localport);
448 449 450 451
		linphone_address_set_domain(contact,localip);
		linphone_address_set_display_name(contact,NULL);

		ret=contact;
452
	}
Simon Morlat's avatar
Simon Morlat committed
453
	linphone_address_unref(proxy);
454 455
	return ret;
}
456

457 458 459 460
void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) {
	if (obj->op && (obj->state == LinphoneRegistrationOk ||
					(obj->state == LinphoneRegistrationProgress && obj->expires != 0))) {
		sal_unregister(obj->op);
461 462
	}
}
463

464 465 466
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
467
		char* proxy_string;
468
		char * from = linphone_address_as_string(cfg->identity_address);
469
		LinphoneAddress *contact;
470
		ms_message("LinphoneProxyConfig [%p] about to register (LinphoneCore version: %s)",cfg,linphone_core_get_version());
471
		proxy_string=linphone_address_as_string_uri_only(proxy);
Simon Morlat's avatar
Simon Morlat committed
472
		linphone_address_unref(proxy);
473 474 475
		if (cfg->op)
			sal_op_release(cfg->op);
		cfg->op=sal_op_new(cfg->lc->sal);
476

477
		linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE);
478

479 480
		if ((contact=guess_contact_for_register(cfg))) {
			sal_op_set_contact_address(cfg->op,contact);
Simon Morlat's avatar
Simon Morlat committed
481
			linphone_address_unref(contact);
482
		}
483

484
		sal_op_set_user_pointer(cfg->op,cfg);
485

486 487 488 489 490 491

		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;
			}
492
			linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,"Registration in progress");
493
		} else {
494
			linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,"Registration failed");
495
		}
496
		ms_free(proxy_string);
497
		ms_free(from);
498
	} else {
499
		/* unregister if registered*/
500 501
		if (cfg->state == LinphoneRegistrationProgress) {
			linphone_proxy_config_set_state(cfg,LinphoneRegistrationCleared,"Registration cleared");
502
		}
503
		_linphone_proxy_config_unregister(cfg);
aymeric's avatar
aymeric committed
504
	}
smorlat's avatar
smorlat committed
505 506
}

507 508 509 510
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");
511
		}
512 513 514
	}
}

515 516 517 518 519 520

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;
	}
521
	if (prefix && prefix[0]!='\0') cfg->dial_prefix=ms_strdup(prefix);
522 523 524 525 526 527 528 529 530 531 532 533 534
}

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;
}
535

536 537
void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t val){
	cfg->quality_reporting_enabled = val;
538 539
}

540
bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg){
541
	return cfg->quality_reporting_enabled;
542 543
}

544
void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, int interval) {
545
	cfg->quality_reporting_interval = interval;
546 547 548 549 550 551
}

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

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

		if (addr){
Simon Morlat's avatar
Simon Morlat committed
565
			linphone_address_unref(addr);
566 567 568 569
		}
	}
}

570 571
const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *cfg){
	return cfg->quality_reporting_collector;
572 573 574
}


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

596
//remove anything but [0-9] and +
597 598 599 600 601
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){
602
		if (*r=='+' || isdigit(*r)){
603 604 605 606 607 608 609
			*w++=*r;
		}
	}
	*w++='\0';
	return result;
}

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

614
static char* replace_icp_with_plus(char *phone, const char *icp){
615 616
	return (strstr(phone, icp) == phone) ?  ms_strdup_printf("+%s", phone+strlen(icp)) : ms_strdup(phone);
}
617

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

627 628 629
char* linphone_proxy_config_normalize_phone_number(LinphoneProxyConfig *proxy, const char *username) {
	LinphoneProxyConfig *tmpproxy = proxy ? proxy : linphone_proxy_config_new();
	char* result = NULL;
630 631 632
	LinphoneDialPlan dialplan = {0};
	char * nationnal_significant_number = NULL;
	int ccc = -1;
633

634 635
	if (linphone_proxy_config_is_phone_number(tmpproxy, username)){
		char * flatten=flatten_number(username);
636
		ms_debug("Flattened number is '%s' for '%s'",flatten, username);
637

638 639
		ccc = linphone_dial_plan_lookup_ccc_from_e164(flatten);
		if (ccc>-1) { /*e164 like phone number*/
640
			dialplan = *linphone_dial_plan_by_ccc_as_int(ccc);
641
			nationnal_significant_number = strstr(flatten, dialplan.ccc);
642 643 644 645 646 647 648 649 650 651 652 653 654
			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));
				}
655 656 657 658 659 660 661 662
				/*it does not make sens to try replace icp with + if we are not sure from the country we are (I.E tmpproxy->dial_prefix==NULL)*/
				if (strstr(flatten,dialplan.icp)==flatten) {
					char *e164 = replace_icp_with_plus(flatten,dialplan.icp);
					result = linphone_proxy_config_normalize_phone_number(tmpproxy,e164);
					ms_free(e164);
					goto end;
				}

663 664
			}
			nationnal_significant_number=flatten;
665
		}
jehan's avatar
jehan committed
666
		ms_debug("Using dial plan '%s'",dialplan.country);
667

668
		/*if proxy has a dial prefix, modify phonenumber accordingly*/
669
		if (dialplan.ccc[0]!='\0') {
670
			/* the number already starts with + or international prefix*/
671 672 673 674 675 676 677 678 679 680 681 682 683 684
			/*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);
685
		}
686 687

	end:
688 689 690 691 692 693
		if (result==NULL) {
			result = flatten;
		} else {
			ms_free(flatten);
		}
	}
694
	if (proxy==NULL) linphone_proxy_config_unref(tmpproxy);
695 696 697 698 699 700 701
	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
702
		linphone_address_unref(addr);
703 704 705 706 707 708 709 710 711 712
		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;

713
	if (!username || *username=='\0') return NULL;
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 740 741 742 743 744

	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);
			}
		}

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

	return NULL;
}

smorlat's avatar
smorlat committed
768 769 770
/**
 * Commits modification made to the proxy configuration.
**/
771
LinphoneStatus linphone_proxy_config_done(LinphoneProxyConfig *cfg)
smorlat's avatar
smorlat committed
772
{
773 774
	LinphoneProxyConfigAddressComparisonResult res;

775
	if (!linphone_proxy_config_check(cfg->lc,cfg))
776 777
		return -1;

778
	/*check if server address has changed*/
779
	res = linphone_proxy_config_is_server_config_changed(cfg);
780
	if (res != LinphoneProxyConfigAddressEqual) {
781
		/* server config has changed, need to unregister from previous first*/
782
		if (cfg->op) {
783
			if (res == LinphoneProxyConfigAddressDifferent) {
784
				_linphone_proxy_config_unregister(cfg);
785
			}
786 787 788
			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;
789
		}
790 791 792 793 794
		if (cfg->long_term_event) {
			if (res == LinphoneProxyConfigAddressDifferent) {
				_linphone_proxy_config_unpublish(cfg);
			}
		}
795
		cfg->commit = TRUE;
796
	}
797
	if (cfg->register_changed){
798
		cfg->commit = TRUE;
799 800 801 802
		cfg->register_changed = FALSE;
	}
	if (cfg->commit){
		linphone_proxy_config_pause_register(cfg);
803
	}
804

805 806 807
	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) {
808
			if (cfg->publish) {
809 810 811 812 813
				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);
				}
814
			}
815 816
			/*publish is terminated*/
			linphone_event_terminate(cfg->long_term_event);
817 818 819 820 821 822
			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);
823
	}
824

825
	linphone_proxy_config_write_all_to_config_file(cfg->lc);
aymeric's avatar
aymeric committed
826 827 828
	return 0;
}

829 830 831 832
const char* linphone_proxy_config_get_realm(const LinphoneProxyConfig *cfg)
{
	return cfg?cfg->realm:NULL;
}
aymeric's avatar
aymeric committed
833 834 835 836 837
void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm)
{
	if (cfg->realm!=NULL) {
		ms_free(cfg->realm);
	}
838
	cfg->realm=ms_strdup(realm);
aymeric's avatar
aymeric committed
839 840
}

841
int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePresenceModel *presence){
842
	int err=0;
843

844
	if (proxy->state==LinphoneRegistrationOk || proxy->state==LinphoneRegistrationCleared){
845 846 847 848 849 850 851
		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));
852
			linphone_event_ref(proxy->long_term_event);
853 854
		}
		proxy->long_term_event->internal = TRUE;
855

856 857 858 859
		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));
		}
860

861
		if (!(presence_body = linphone_presence_model_to_xml(presence))) {
862
			ms_error("Cannot publish presence model [%p] for proxy config [%p] because of xml serialization error",presence,proxy);
863
			return -1;
864
		}
865

866 867 868 869
		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");
870 871 872 873 874
		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;
		}
875 876
		err = linphone_event_send_publish(proxy->long_term_event, content);
		linphone_content_unref(content);
Ghislain MARY's avatar
Ghislain MARY committed
877
		ms_free(presence_body);
878
	}else proxy->send_publish=TRUE; /*otherwise do not send publish if registration is in progress, this will be done later*/
879
	return err;
aymeric's avatar
aymeric committed
880 881
}

882 883 884
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
885
					(linphone_event_get_publish_state(obj->long_term_event)  == LinphonePublishProgress && obj->publish_expires != 0))) {
886 887
		linphone_event_unpublish(obj->long_term_event);
	}
888 889 890 891
	if (obj->sip_etag) {
		ms_free(obj->sip_etag);
		obj->sip_etag=NULL;
	}
892 893
}

894 895
const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *cfg){
	return cfg->reg_route;
896 897
}

898 899
const LinphoneAddress *linphone_proxy_config_get_identity_address(const LinphoneProxyConfig *cfg){
	return cfg->identity_address;
900 901
}

902 903
const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *cfg){
	return cfg->reg_identity;
904 905
}

906 907
bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *cfg){
	return cfg->publish;
908 909
}

910 911
const char *linphone_proxy_config_get_server_addr(const LinphoneProxyConfig *cfg){
	return cfg->reg_proxy;
912 913 914
}

/**
915
 * @return the duration of registration.
916
**/
917 918
int linphone_proxy_config_get_expires(const LinphoneProxyConfig *cfg){
	return cfg->expires;
919 920
}

921 922 923 924 925 926 927 928
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;
929 930
	}
	if (contact_params){
931
		cfg->contact_params=ms_strdup(contact_params);
932
	}
933
	cfg->register_changed = TRUE;
934 935
}

936 937 938 939
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;
940 941
	}
	if (contact_uri_params){
942
		cfg->contact_uri_params=ms_strdup(contact_uri_params);
943
	}
944
	cfg->register_changed = TRUE;
945 946
}

947 948
const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *cfg){
	return cfg->contact_params;
949 950
}

951 952
const char *linphone_proxy_config_get_contact_uri_parameters(const LinphoneProxyConfig *cfg){
	return cfg->contact_uri_params;
953 954
}

955 956
struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *cfg){
	return cfg->lc;
957
}
smorlat's avatar
smorlat committed
958

959 960 961 962 963 964 965 966 967
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);
968
	cfg->register_changed = TRUE;
969 970
}

971
LinphoneStatus linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){
972 973 974
	if (!linphone_proxy_config_check(lc,cfg)) {
		return -1;
	}
975
	if (bctbx_list_find(lc->sip_conf.proxies,cfg)!=NULL){
976 977 978
		ms_warning("ProxyConfig already entered, ignored.");
		return 0;
	}
979
	lc->sip_conf.proxies=bctbx_list_append(lc->sip_conf.proxies,(void *)linphone_proxy_config_ref(cfg));
aymeric's avatar
aymeric committed
980 981 982 983 984
	linphone_proxy_config_apply(cfg,lc);
	return 0;
}

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

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

998
	cfg->deletion_date=ms_time(NULL);
999
	if (cfg->state==LinphoneRegistrationOk){
1000
		/* UNREGISTER */
1001
		linphone_proxy_config_edit(cfg);
1002 1003
		linphone_proxy_config_enable_register(cfg,FALSE);
		linphone_proxy_config_done(cfg);
1004
		linphone_proxy_config_update(cfg);
1005 1006
	} else if (cfg->state != LinphoneRegistrationNone) {
		linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone,"Registration disabled");
1007
	}
1008
	linphone_proxy_config_write_all_to_config_file(lc);
aymeric's avatar
aymeric committed
1009
}
1010

1011
void linphone_core_clear_proxy_config(LinphoneCore *lc){
1012 1013
	bctbx_list_t* list=bctbx_list_copy(linphone_core_get_proxy_config_list((const LinphoneCore*)lc));
	bctbx_list_t* copy=list;
1014
	for(;list!=NULL;list=list->next){
1015 1016
		linphone_core_remove_proxy_config(lc,(LinphoneProxyConfig *)list->data);
	}
1017
	bctbx_list_free(copy);
1018
	linphone_proxy_config_write_all_to_config_file(lc);
1019
}
1020

1021
int linphone_core_get_default_proxy_config_index(LinphoneCore *lc) {
1022 1023
	int pos = -1;
	if (lc->default_proxy != NULL) {
1024
		pos = bctbx_list_position(lc->sip_conf.proxies, bctbx_list_find(lc->sip_conf.proxies, (void *)lc->default_proxy));
1025 1026 1027 1028 1029
	}
	return pos;
}

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

void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index){
	if (index<0) linphone_core_set_default_proxy(lc,NULL);
1045
	else linphone_core_set_default_proxy(lc,bctbx_list_nth_data(lc->sip_conf.proxies,index));
aymeric's avatar
aymeric committed
1046 1047 1048 1049
}

int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config){
	if (config!=NULL) *config=lc->default_proxy;
1050 1051 1052 1053 1054
	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
1055 1056
}

1057
const bctbx_list_t *linphone_core_get_proxy_config_list(const LinphoneCore *lc){
aymeric's avatar
aymeric committed
1058 1059 1060
	return lc->sip_conf.proxies;
}

1061
void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyConfig *cfg, int index)
aymeric's avatar
aymeric committed
1062 1063 1064 1065 1066
{
	char key[50];

	sprintf(key,"proxy_%i",index);
	lp_config_clean_section(config,key);
1067
	if (cfg==NULL){
aymeric's avatar
aymeric committed
1068 1069
		return;
	}
1070 1071
	if (cfg->type!=NULL){
		lp_config_set_string(config,key,"type",cfg->type);
smorlat's avatar
smorlat committed
1072
	}
1073 1074
	if (cfg->reg_proxy!=NULL){
		lp_config_set_string(config,key,"reg_proxy",cfg->reg_proxy);
aymeric's avatar
aymeric committed
1075
	}
1076 1077
	if (cfg->reg_route!=NULL){
		lp_config_set_string(config,key,"reg_route",cfg->reg_route);
aymeric's avatar
aymeric committed
1078
	}
1079 1080
	if (cfg->reg_identity!=NULL){
		lp_config_set_string(config,key,"reg_identity",cfg->reg_identity);
aymeric's avatar
aymeric committed
1081
	}
1082 1083
	if (cfg->realm!=NULL){
		lp_config_set_string(config,key,"realm",cfg->realm);
1084
	}
1085 1086
	if (cfg->contact_params!=NULL){
		lp_config_set_string(config,key,"contact_parameters",cfg->contact_params);
Simon Morlat's avatar
Simon Morlat committed
1087
	}
1088 1089
	if (cfg->contact_uri_params!=NULL){
		lp_config_set_string(config,key,"contact_uri_parameters",cfg->contact_uri_params);
1090
	}
1091 1092
	if (cfg->quality_reporting_collector!=NULL){
		lp_config_set_string(config,key,"quality_reporting_collector",cfg->quality_reporting_collector);
1093
	}