proxy.c 64.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

aymeric's avatar
aymeric committed
21
#include "linphonecore.h"
smorlat's avatar
smorlat committed
22
#include "sipsetup.h"
aymeric's avatar
aymeric committed
23 24
#include "lpconfig.h"
#include "private.h"
25
#include "mediastreamer2/mediastream.h"
aymeric's avatar
aymeric committed
26

27 28
#include <ctype.h>

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/*store current config related to server location*/
static void linphone_proxy_config_store_server_config(LinphoneProxyConfig* obj) {
	if (obj->saved_identity) linphone_address_destroy(obj->saved_identity);
	if (obj->reg_identity)
		obj->saved_identity = linphone_address_new(obj->reg_identity);
	else
		obj->saved_identity = NULL;

	if (obj->saved_proxy) linphone_address_destroy(obj->saved_proxy);
	if (obj->reg_proxy)
		obj->saved_proxy = linphone_address_new(obj->reg_proxy);
	else
		obj->saved_proxy = NULL;
}

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

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

62
LinphoneProxyConfigAddressComparisonResult linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj) {
63 64
	LinphoneAddress *current_identity=obj->reg_identity?linphone_address_new(obj->reg_identity):NULL;
	LinphoneAddress *current_proxy=obj->reg_proxy?linphone_address_new(obj->reg_proxy):NULL;
65 66
	LinphoneProxyConfigAddressComparisonResult result_identity;
	LinphoneProxyConfigAddressComparisonResult result;
67

68 69
	result = linphone_proxy_config_address_equal(obj->saved_identity,current_identity);
	if (result == LinphoneProxyConfigAddressDifferent) goto end;
70
	result_identity = result;
71 72 73

	result = linphone_proxy_config_address_equal(obj->saved_proxy,current_proxy);
	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 81 82 83
	end:
	if (current_identity) linphone_address_destroy(current_identity);
	if (current_proxy) linphone_address_destroy(current_proxy);
	return result;
84
}
85

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

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

100 101 102 103 104
static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *obj) {
	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

110
	obj->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600;
111
	obj->reg_sendregister = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 1) : 1;
112 113 114 115 116 117
	obj->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL;
	obj->dial_escape_plus = lc ? lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0;
	obj->privacy = lc ? lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault;
	obj->reg_identity = identity ? ms_strdup(identity) : NULL;
	obj->reg_proxy = proxy ? ms_strdup(proxy) : NULL;
	obj->reg_route = route ? ms_strdup(route) : NULL;
118
	obj->domain = NULL;
119
	obj->realm = realm ? ms_strdup(realm) : NULL;
120
	obj->quality_reporting_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0;
121 122
	obj->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL;
	obj->quality_reporting_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_interval", 0) : 0;
123 124
	obj->contact_params = contact_params ? ms_strdup(contact_params) : NULL;
	obj->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL;
125
	obj->avpf_mode = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf", LinphoneAVPFDefault) : LinphoneAVPFDefault;
126
	obj->avpf_rr_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf_rr_interval", 5) : 5;
127
	obj->publish_expires=-1;
aymeric's avatar
aymeric committed
128 129
}

smorlat's avatar
smorlat committed
130 131 132 133 134 135
/**
 * @addtogroup proxies
 * @{
**/

/**
jehan's avatar
jehan committed
136 137
 * @deprecated, use #linphone_core_create_proxy_config instead
 *Creates an empty proxy config.
smorlat's avatar
smorlat committed
138
**/
jehan's avatar
jehan committed
139 140 141
LinphoneProxyConfig *linphone_proxy_config_new() {
	return linphone_core_create_proxy_config(NULL);
}
142

143 144 145 146 147 148 149 150 151 152 153
static void _linphone_proxy_config_destroy(LinphoneProxyConfig *obj);

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

jehan's avatar
jehan committed
154
LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) {
155
	LinphoneProxyConfig *obj = belle_sip_object_new(LinphoneProxyConfig);
jehan's avatar
jehan committed
156
	linphone_proxy_config_init(lc,obj);
aymeric's avatar
aymeric committed
157 158 159
	return obj;
}

160 161 162 163 164 165 166 167 168 169 170
void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj){
	if (obj->op) {
		sal_op_release(obj->op);
		obj->op=NULL;
	}
	if (obj->publish_op){
		sal_op_release(obj->publish_op);
		obj->publish_op=NULL;
	}
}

171
void _linphone_proxy_config_destroy(LinphoneProxyConfig *obj){
aymeric's avatar
aymeric committed
172 173 174
	if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy);
	if (obj->reg_identity!=NULL) ms_free(obj->reg_identity);
	if (obj->reg_route!=NULL) ms_free(obj->reg_route);
175
	if (obj->quality_reporting_collector!=NULL) ms_free(obj->quality_reporting_collector);
smorlat's avatar
smorlat committed
176
	if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx);
177
	if (obj->domain!=NULL) ms_free(obj->domain);
smorlat's avatar
smorlat committed
178
	if (obj->realm!=NULL) ms_free(obj->realm);
smorlat's avatar
smorlat committed
179
	if (obj->type!=NULL) ms_free(obj->type);
180
	if (obj->dial_prefix!=NULL) ms_free(obj->dial_prefix);
181
	if (obj->contact_params) ms_free(obj->contact_params);
182
	if (obj->contact_uri_params) ms_free(obj->contact_uri_params);
183
	if (obj->saved_proxy!=NULL) linphone_address_destroy(obj->saved_proxy);
Simon Morlat's avatar
Simon Morlat committed
184
	if (obj->saved_identity!=NULL) linphone_address_destroy(obj->saved_identity);
185
	if (obj->sent_headers!=NULL) sal_custom_header_free(obj->sent_headers);
186
	_linphone_proxy_config_release_ops(obj);
187 188 189 190 191 192 193 194 195 196 197 198 199
}

/**
 * Destroys a proxy config.
 * @deprecated
 *
 * @note: LinphoneProxyConfig that have been removed from LinphoneCore with
 * linphone_core_remove_proxy_config() must not be freed.
**/
void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg) {
	belle_sip_object_unref(cfg);
}

200 201 202 203 204
void _linphone_proxy_config_release(LinphoneProxyConfig *cfg) {
	_linphone_proxy_config_release_ops(cfg);
	belle_sip_object_unref(cfg);
}

205 206 207 208 209 210 211
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
212 213
}

smorlat's avatar
smorlat committed
214 215
/**
 * Returns a boolean indicating that the user is sucessfully registered on the proxy.
216
 * @deprecated Use linphone_proxy_config_get_state() instead.
smorlat's avatar
smorlat committed
217
**/
smorlat's avatar
smorlat committed
218
bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){
219
	return obj->state == LinphoneRegistrationOk;
smorlat's avatar
smorlat committed
220 221
}

smorlat's avatar
smorlat committed
222 223 224 225 226 227 228 229
/**
 * Sets the proxy address
 *
 * Examples of valid sip proxy address are:
 * - IP address: sip:87.98.157.38
 * - IP address with port: sip:87.98.157.38:5062
 * - hostnames : sip:sip.example.net
**/
aymeric's avatar
aymeric committed
230
int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){
231 232
	LinphoneAddress *addr=NULL;
	char *modified=NULL;
233

aymeric's avatar
aymeric committed
234 235
	if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy);
	obj->reg_proxy=NULL;
236

aymeric's avatar
aymeric committed
237
	if (server_addr!=NULL && strlen(server_addr)>0){
238
		if (strstr(server_addr,"sip:")==NULL && strstr(server_addr,"sips:")==NULL){
239 240 241
			modified=ms_strdup_printf("sip:%s",server_addr);
			addr=linphone_address_new(modified);
			ms_free(modified);
242
		}
243 244
		if (addr==NULL)
			addr=linphone_address_new(server_addr);
245
		if (addr){
246
			obj->reg_proxy=linphone_address_as_string(addr);
247
			linphone_address_destroy(addr);
aymeric's avatar
aymeric committed
248 249
		}else{
			ms_warning("Could not parse %s",server_addr);
250
			return -1;
aymeric's avatar
aymeric committed
251 252 253 254 255
		}
	}
	return 0;
}

smorlat's avatar
smorlat committed
256 257 258
/**
 * Sets the user identity as a SIP address.
 *
259
 * This identity is normally formed with display name, username and domain, such
smorlat's avatar
smorlat committed
260 261 262 263 264
 * as:
 * Alice <sip:alice@example.net>
 * The REGISTER messages will have from and to set to this identity.
 *
**/
265 266
int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity){
	LinphoneAddress *addr;
aymeric's avatar
aymeric committed
267
	if (identity!=NULL && strlen(identity)>0){
268 269 270 271 272 273 274 275 276 277 278 279
		addr=linphone_address_new(identity);
		if (!addr || linphone_address_get_username(addr)==NULL){
			ms_warning("Invalid sip identity: %s",identity);
			if (addr)
				linphone_address_destroy(addr);
			return -1;
		}else{
			if (obj->reg_identity!=NULL) {
				ms_free(obj->reg_identity);
				obj->reg_identity=NULL;
			}
			obj->reg_identity=ms_strdup(identity);
280 281
			if (obj->domain){
				ms_free(obj->domain);
282
			}
283
			obj->domain=ms_strdup(linphone_address_get_domain(addr));
284 285
			linphone_address_destroy(addr);
			return 0;
aymeric's avatar
aymeric committed
286 287
		}
	}
288
	return -1;
smorlat's avatar
smorlat committed
289 290 291
}

const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg){
292
	return cfg->domain;
aymeric's avatar
aymeric committed
293 294
}

smorlat's avatar
smorlat committed
295 296 297 298 299
/**
 * Sets a SIP route.
 * When a route is set, all outgoing calls will go to the route's destination if this proxy
 * is the default one (see linphone_core_set_default_proxy() ).
**/
300
int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route)
aymeric's avatar
aymeric committed
301
{
302 303
	if (obj->reg_route!=NULL){
		ms_free(obj->reg_route);
aymeric's avatar
aymeric committed
304 305
		obj->reg_route=NULL;
	}
306
	if (route!=NULL && route[0] !='\0'){
307 308
		SalAddress *addr;
		char *tmp;
Simon Morlat's avatar
Simon Morlat committed
309
		/*try to prepend 'sip:' */
310
		if (strstr(route,"sip:")==NULL && strstr(route,"sips:")==NULL){
311 312 313 314 315 316 317 318 319 320
			tmp=ms_strdup_printf("sip:%s",route);
		}else tmp=ms_strdup(route);
		addr=sal_address_new(tmp);
		if (addr!=NULL){
			sal_address_destroy(addr);
		}else{
			ms_free(tmp);
			tmp=NULL;
		}
		obj->reg_route=tmp;
Simon Morlat's avatar
Simon Morlat committed
321
	}
322
	return 0;
aymeric's avatar
aymeric committed
323 324 325 326
}

bool_t linphone_proxy_config_check(LinphoneCore *lc, LinphoneProxyConfig *obj){
	if (obj->reg_proxy==NULL){
327 328
		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
329 330 331 332
						" followed by a hostname."));
		return FALSE;
	}
	if (obj->reg_identity==NULL){
333 334
		if (lc)
			linphone_core_notify_display_warning(lc,_("The sip identity you entered is invalid.\nIt should look like "
aymeric's avatar
aymeric committed
335 336 337 338 339 340
					"sip:username@proxydomain, such as sip:alice@example.net"));
		return FALSE;
	}
	return TRUE;
}

smorlat's avatar
smorlat committed
341 342 343
/**
 * Indicates whether a REGISTER request must be sent to the proxy.
**/
aymeric's avatar
aymeric committed
344 345 346 347
void linphone_proxy_config_enableregister(LinphoneProxyConfig *obj, bool_t val){
	obj->reg_sendregister=val;
}

smorlat's avatar
smorlat committed
348 349 350
/**
 * Sets the registration expiration time in seconds.
**/
351
void linphone_proxy_config_set_expires(LinphoneProxyConfig *obj, int val){
352
	if (val<0) val=600;
aymeric's avatar
aymeric committed
353 354 355 356 357 358
	obj->expires=val;
}

void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){
	obj->publish=val;
}
359 360 361

/**
 * Prevent a proxy config from refreshing its registration.
362
 * This is useful to let registrations to expire naturally (or) when the application wants to keep control on when
363 364 365 366 367 368 369 370 371
 * refreshes are sent.
 * However, linphone_core_set_network_reachable(lc,TRUE) will always request the proxy configs to refresh their registrations.
 * The refreshing operations can be resumed with linphone_proxy_config_refresh_register().
 * @param obj the proxy config
**/
void linphone_proxy_config_pause_register(LinphoneProxyConfig *obj){
	if (obj->op) sal_op_stop_refreshing(obj->op);
}

smorlat's avatar
smorlat committed
372 373 374 375 376 377 378 379 380
/**
 * Starts editing a proxy configuration.
 *
 * Because proxy configuration must be consistent, applications MUST
 * call linphone_proxy_config_edit() before doing any attempts to modify
 * proxy configuration (such as identity, proxy address and so on).
 * Once the modifications are done, then the application must call
 * linphone_proxy_config_done() to commit the changes.
**/
aymeric's avatar
aymeric committed
381
void linphone_proxy_config_edit(LinphoneProxyConfig *obj){
Simon Morlat's avatar
Simon Morlat committed
382
	if (obj->publish && obj->publish_op){
383 384 385 386
	        /*unpublish*/
	        sal_publish_presence(obj->publish_op,NULL,NULL,0,(SalPresenceModel *)NULL);
	        sal_op_release(obj->publish_op);
	        obj->publish_op=NULL;
aymeric's avatar
aymeric committed
387
	}
388 389 390 391
	/*store current config related to server location*/
	linphone_proxy_config_store_server_config(obj);

	/*stop refresher in any case*/
392
	linphone_proxy_config_pause_register(obj);
aymeric's avatar
aymeric committed
393 394
}

Simon Morlat's avatar
Simon Morlat committed
395
void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc){
aymeric's avatar
aymeric committed
396 397 398
	obj->lc=lc;
	linphone_proxy_config_done(obj);
}
Simon Morlat's avatar
Simon Morlat committed
399

400 401 402 403 404 405 406 407 408 409 410
void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj){
	if (obj->publish_op){
		sal_op_release(obj->publish_op);
		obj->publish_op=NULL;
	}
	if (obj->op){
		sal_op_release(obj->op);
		obj->op=NULL;
	}
}

411 412 413
LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){
	LinphoneAddress *ret=NULL;
	LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy);
414
	const char *host;
415

416
	if (proxy==NULL) return NULL;
417
	host=linphone_address_get_domain(proxy);
418
	if (host!=NULL){
419 420
		int localport = -1;
		const char *localip = NULL;
421
		LinphoneAddress *contact=linphone_address_new(obj->reg_identity);
422

Simon Morlat's avatar
Simon Morlat committed
423
		linphone_address_clean(contact);
424

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

		ret=contact;
444
	}
445
	linphone_address_destroy(proxy);
446 447
	return ret;
}
448

449 450 451 452
/**
 * unregister without moving the register_enable flag
 */
void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) {
453
	if (obj->op && obj->state == LinphoneRegistrationOk) {
454 455 456
		sal_unregister(obj->op);
	}
}
457

smorlat's avatar
smorlat committed
458
static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
aymeric's avatar
aymeric committed
459
	if (obj->reg_sendregister){
Simon Morlat's avatar
Simon Morlat committed
460
		LinphoneAddress* proxy=linphone_address_new(obj->reg_proxy);
461
		LinphoneAddress* to=linphone_address_new(obj->reg_identity);
Simon Morlat's avatar
Simon Morlat committed
462
		char* proxy_string;
463
		LinphoneAddress *contact;
464
		ms_message("LinphoneProxyConfig [%p] about to register (LinphoneCore version: %s)",obj,linphone_core_get_version());
jehan's avatar
jehan committed
465 466
		proxy_string=linphone_address_as_string_uri_only(proxy);
		linphone_address_destroy(proxy);
467 468 469
		if (obj->op)
			sal_op_release(obj->op);
		obj->op=sal_op_new(obj->lc->sal);
470

471
		linphone_configure_op(obj->lc, obj->op, to, obj->sent_headers, FALSE);
472 473
		linphone_address_destroy(to);

jehan's avatar
jehan committed
474
		if ((contact=guess_contact_for_register(obj))) {
475
			sal_op_set_contact_address(obj->op,contact);
Simon Morlat's avatar
Simon Morlat committed
476
			linphone_address_destroy(contact);
jehan's avatar
jehan committed
477
		}
478

Simon Morlat's avatar
Simon Morlat committed
479
		sal_op_set_user_pointer(obj->op,obj);
480 481


jehan's avatar
jehan committed
482
		if (sal_register(obj->op,proxy_string,obj->reg_identity,obj->expires)==0) {
483
			linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress,"Registration in progress");
484
		} else {
485
			linphone_proxy_config_set_state(obj,LinphoneRegistrationFailed,"Registration failed");
486
		}
jehan's avatar
jehan committed
487
		ms_free(proxy_string);
488
	} else {
489 490 491 492 493
		/* unregister if registered*/
		if (obj->state == LinphoneRegistrationProgress) {
			linphone_proxy_config_set_state(obj,LinphoneRegistrationCleared,"Registration cleared");
		}
		_linphone_proxy_config_unregister(obj);
aymeric's avatar
aymeric committed
494
	}
smorlat's avatar
smorlat committed
495 496
}

497 498 499 500 501
/**
 * Refresh a proxy registration.
 * This is useful if for example you resuming from suspend, thus IP address may have changed.
**/
void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj){
502
	if (obj->reg_sendregister && obj->op && obj->state!=LinphoneRegistrationProgress){
503 504 505
		if (sal_register_refresh(obj->op,obj->expires) == 0) {
			linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress, "Refresh registration");
		}
506 507 508
	}
}

509 510

/**
511
 * Sets a dialing prefix to be automatically prepended when inviting a number with
512
 * linphone_core_invite();
513
 * This dialing prefix shall usually be the country code of the country where the user is living, without "+".
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
}

/**
 * Returns dialing prefix.
 *
527
 *
528 529 530 531 532 533
**/
const char *linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg){
	return cfg->dial_prefix;
}

/**
534
 * Sets whether liblinphone should replace "+" by international calling prefix in dialed numbers (passed to
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
 * #linphone_core_invite ).
 *
**/
void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val){
	cfg->dial_escape_plus=val;
}

/**
 * Returns whether liblinphone should replace "+" by "00" in dialed numbers (passed to
 * #linphone_core_invite ).
 *
**/
bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg){
	return cfg->dial_escape_plus;
}
550

551 552
void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t val){
	cfg->quality_reporting_enabled = val;
553 554
}

555
bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg){
556
	// ensure that collector address is set too!
557
	return cfg->quality_reporting_enabled && cfg->quality_reporting_collector != NULL;
558 559
}

560
void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval) {
561
	cfg->quality_reporting_interval = interval;
562 563 564 565 566 567
}

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

568
void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector){
569 570
	if (collector!=NULL && strlen(collector)>0){
		LinphoneAddress *addr=linphone_address_new(collector);
571
		if (!addr){
572
			ms_error("Invalid SIP collector URI: %s. Quality reporting will be DISABLED.",collector);
573
		} else {
574
			if (cfg->quality_reporting_collector != NULL){
575
				ms_free(cfg->quality_reporting_collector);
576
			}
577
			cfg->quality_reporting_collector = ms_strdup(collector);
578 579 580
		}

		if (addr){
581 582 583 584 585
			linphone_address_destroy(addr);
		}
	}
}

586 587
const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *cfg){
	return cfg->quality_reporting_collector;
588 589 590
}


591 592 593 594 595 596
/*
 * http://en.wikipedia.org/wiki/Telephone_numbering_plan
 * http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe
 */
typedef struct dial_plan{
	const char *country;
597
	const char* iso_country_code; /* ISO 3166-1 alpha-2 code, ex: FR for France*/
598 599 600
	char  ccc[8]; /*country calling code*/
	int nnl; /*maximum national number length*/
	const char * icp; /*international call prefix, ex: 00 in europe*/
601

602 603 604
}dial_plan_t;

/* TODO: fill with information for all countries over the world*/
605

606
static dial_plan_t const dial_plans[]={
607
	//Country					, iso country code, e164 country calling code, number length, international usual prefix
jehan's avatar
jehan committed
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
	{"Afghanistan"                  ,"AF"		, "93"      , 9		, "00"  },
	{"Albania"                      ,"AL"		, "355"     , 9		, "00"  },
	{"Algeria"                      ,"DZ"		, "213"     , 9		, "00"  },
	{"American Samoa"               ,"AS"		, "1"       , 10	, "011"	},
	{"Andorra"                      ,"AD"		, "376"     , 6		, "00"  },
	{"Angola"                       ,"AO"		, "244"     , 9		, "00"  },
	{"Anguilla"                     ,"AI"		, "1"       , 10	, "011" },
	{"Antigua and Barbuda"          ,"AG"		, "1"       , 10	, "011"	},
	{"Argentina"                    ,"AR"		, "54"      , 10	, "00"  },
	{"Armenia"                      ,"AM"		, "374"     , 8		, "00"  },
	{"Aruba"                        ,"AW"		, "297"     , 7		, "011"	},
	{"Australia"                    ,"AU"		, "61"      , 9	    , "0011"},
	{"Austria"                      ,"AT"		, "43"      , 10	, "00"  },
	{"Azerbaijan"                   ,"AZ"       , "994"     , 9		, "00"  },
	{"Bahamas"                      ,"BS"		, "1"       , 10    , "011"	},
	{"Bahrain"                      ,"BH"		, "973"     , 8     , "00"  },
	{"Bangladesh"                   ,"BD"		, "880"     , 10    , "00"  },
	{"Barbados"                     ,"BB"		, "1"       , 10    , "011"	},
626
	{"Belarus"                      ,"BY"		, "375"     , 9     , "00"  },
jehan's avatar
jehan committed
627 628 629 630 631 632 633 634
	{"Belgium"                      ,"BE"		, "32"      , 9     , "00"  },
	{"Belize"                       ,"BZ"		, "501"     , 7     , "00"  },
	{"Benin"                        ,"BJ"		, "229"     , 8     , "00"	},
	{"Bermuda"                      ,"BM"		, "1"       , 10    , "011" },
	{"Bhutan"                       ,"BT"		, "975"     , 8     , "00"  },
	{"Bolivia"                      ,"BO"		, "591"     , 8     , "00"	},
	{"Bosnia and Herzegovina"       ,"BA"		, "387"     , 8     , "00"  },
	{"Botswana"                     ,"BW"		, "267"     , 8     , "00"  },
635
	{"Brazil"                       ,"BR"		, "55"      , 10	, "00"  },
jehan's avatar
jehan committed
636 637 638 639
	{"Brunei Darussalam"            ,"BN"		, "673"     , 7		, "00"	},
	{"Bulgaria"                     ,"BG"		, "359"     , 9		, "00"  },
	{"Burkina Faso"                 ,"BF"		, "226"     , 8		, "00"  },
	{"Burundi"                      ,"BI"		, "257"     , 8     , "011" },
640
	{"Cambodia"                     ,"KH"		, "855"     , 9		, "00"  },
jehan's avatar
jehan committed
641 642 643 644 645 646 647 648
	{"Cameroon"                     ,"CM"		, "237"     , 8		, "00"  },
	{"Canada"                       ,"CA"		, "1"       , 10	, "011" },
	{"Cape Verde"                   ,"CV"		, "238"     , 7		, "00"	},
	{"Cayman Islands"               ,"KY"		, "1"       , 10	, "011" },
	{"Central African Republic"     ,"CF"		, "236"     , 8     , "00"  },
	{"Chad"                         ,"TD"		, "235"     , 8		, "00"	},
	{"Chile"                        ,"CL"		, "56"      , 9	    , "00"  },
	{"China"                        ,"CN"		, "86"      , 11	, "00"  },
649 650 651 652 653 654
	{"Colombia"                     ,"CO"       , "57"      , 10	, "00"  },
	{"Comoros"                      ,"KM"		, "269"     , 7     , "00"	},
	{"Congo"                        ,"CG"		, "242"     , 9		, "00"	},
	{"Congo Democratic Republic"	,"CD"		, "243"     , 9		, "00"  },
	{"Cook Islands"                 ,"CK"		, "682"     , 5		, "00"  },
	{"Costa Rica"                   ,"CR"		, "506"     , 8     , "00"	},
655
	{"Cote d'Ivoire"	            ,"AD"		, "225"     , 8     , "00"  },
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
	{"Croatia"                      ,"HR"		, "385"     , 9		, "00"  },
	{"Cuba"                         ,"CU"		, "53"      , 8     , "119" },
	{"Cyprus"                       ,"CY"		, "357"     , 8     , "00"	},
	{"Czech Republic"               ,"CZ"		, "420"     , 9     , "00"  },
	{"Denmark"                      ,"DK"		, "45"      , 8		, "00"  },
	{"Djibouti"                     ,"DJ"		, "253"     , 8		, "00"	},
	{"Dominica"                     ,"DM"		, "1"       , 10	, "011" },
	{"Dominican Republic"	        ,"DO"		, "1"       , 10	, "011" },
	{"Ecuador"                      ,"EC"       , "593"     , 9		, "00"  },
	{"Egypt"                        ,"EG"		, "20"      , 10	, "00"	},
	{"El Salvador"                  ,"SV"		, "503"     , 8		, "00"	},
	{"Equatorial Guinea"            ,"GQ"		, "240"     , 9		, "00"  },
	{"Eritrea"                      ,"ER"		, "291"     , 7		, "00"  },
	{"Estonia"                      ,"EE"		, "372"     , 8     , "00"	},
	{"Ethiopia"                     ,"ET"		, "251"     , 9     , "00"  },
	{"Falkland Islands"	            ,"FK"		, "500"     , 5		, "00"  },
	{"Faroe Islands"	            ,"FO"		, "298"     , 6     , "00"  },
	{"Fiji"                         ,"FJ"		, "679"     , 7     , "00"	},
	{"Finland"                      ,"FI"		, "358"     , 9     , "00"  },
	{"France"                       ,"FR"		, "33"      , 9		, "00"	},
	{"French Guiana"				,"GF"		, "594"     , 9		, "00"	},
	{"French Polynesia"             ,"PF"		, "689"     , 6	    , "00"  },
	{"Gabon"                        ,"GA"		, "241"     , 8     , "00"  },
	{"Gambia"                       ,"GM"       , "220"     , 7		, "00"  },
	{"Georgia"                      ,"GE"		, "995"     , 9     , "00"	},
	{"Germany"                      ,"DE"		, "49"      , 11	, "00"	},
	{"Ghana"                        ,"GH"		, "233"     , 9		, "00"  },
	{"Gibraltar"                    ,"GI"		, "350"     , 8		, "00"  },
	{"Greece"                       ,"GR"		, "30"      ,10     , "00"	},
	{"Greenland"                    ,"GL"		, "299"     , 6		, "00"  },
	{"Grenada"                      ,"GD"		, "1"       , 10	, "011" },
	{"Guadeloupe"                   ,"GP"		, "590"     , 9     , "00"  },
	{"Guam"                         ,"GU"		, "1"       , 10	, "011"	},
	{"Guatemala"                    ,"GT"		, "502"     , 8     , "00"  },
	{"Guinea"                       ,"GN"		, "224"     , 8		, "00"  },
	{"Guinea-Bissau"				,"GW"		, "245"     , 7		, "00"	},
	{"Guyana"                       ,"GY"		, "592"     , 7	    , "001" },
	{"Haiti"                        ,"HT"		, "509"     , 8     , "00"  },
	{"Honduras"                     ,"HN"       , "504"     , 8		, "00"  },
	{"Hong Kong"                    ,"HK"		, "852"     , 8     , "001"	},
	{"Hungary"                      ,"HU"		, "36"      , 9     , "00"  },
	{"Iceland"                      ,"IS"		, "354"     , 9     , "00"  },
	{"India"                        ,"IN"		, "91"      , 10    , "00"  },
	{"Indonesia"                    ,"ID"		, "62"      , 10	, "001"	},
	{"Iran"                         ,"IR"		, "98"      , 10	, "00"	},
	{"Iraq"                         ,"IQ"		, "964"     , 10	, "00"  },
	{"Ireland"                      ,"IE"		, "353"     , 9		, "00"  },
	{"Israel"                       ,"IL"		, "972"     , 9     , "00"	},
	{"Italy"                        ,"IT"		, "39"      , 10	, "00"  },
705
	{"Jersey"                       ,"JE"		, "44"      , 10	, "00"	},
706 707 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 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
	{"Jamaica"                      ,"JM"		, "1"       , 10	, "011" },
	{"Japan"                        ,"JP"		, "81"      , 10	, "010" },
	{"Jordan"                       ,"JO"		, "962"     , 9     , "00"	},
	{"Kazakhstan"                   ,"KZ"		, "7"       , 10    , "00"  },
	{"Kenya"                        ,"KE"		, "254"     , 9		, "000" },
	{"Kiribati"                     ,"KI"		, "686"     , 5		, "00"	},
	{"Korea, North"                 ,"KP"		, "850"     , 12	, "99"  },
	{"Korea, South"                 ,"KR"       , "82"      , 12	, "001" },
	{"Kuwait"                       ,"KW"		, "965"     , 8     , "00"	},
	{"Kyrgyzstan"                   ,"KG"		, "996"     , 9     , "00"  },
	{"Laos"                         ,"LA"		, "856"     , 10    , "00"  },
	{"Latvia"                       ,"LV"		, "371"     , 8     , "00"	},
	{"Lebanon"                      ,"LB"		, "961"     , 7     , "00"	},
	{"Lesotho"                      ,"LS"		, "266"     , 8		, "00"	},
	{"Liberia"                      ,"LR"		, "231"     , 8		, "00"  },
	{"Libya"                        ,"LY"		, "218"     , 8		, "00"  },
	{"Liechtenstein"                ,"LI"		, "423"     , 7     , "00"	},
	{"Lithuania"                    ,"LT"		, "370"     , 8		, "00"  },
	{"Luxembourg"                   ,"LU"		, "352"     , 9		, "00"  },
	{"Macau"                        ,"MO"		, "853"     , 8     , "00"  },
	{"Macedonia"                    ,"MK"		, "389"     , 8     , "00"	},
	{"Madagascar"                   ,"MG"		, "261"     , 9     , "00"  },
	{"Malawi"                       ,"MW"		, "265"     , 9		, "00"  },
	{"Malaysia"                     ,"MY"		, "60"      , 9		, "00"	},
	{"Maldives"                     ,"MV"		, "960"     , 7	    , "00"  },
	{"Mali"                         ,"ML"		, "223"     , 8     , "00"  },
	{"Malta"                        ,"MT"       , "356"     , 8		, "00"  },
	{"Marshall Islands"				,"MH"		, "692"     , 7     , "011"	},
	{"Martinique"                   ,"MQ"		, "596"     , 9     , "00"  },
	{"Mauritania"                   ,"MR"		, "222"     , 8     , "00"  },
	{"Mauritius"                    ,"MU"		, "230"     , 7     , "00"	},
	{"Mayotte Island"               ,"YT"		, "262"     , 9     , "00"	},
	{"Mexico"                       ,"MX"		, "52"      , 10	, "00"	},
	{"Micronesia"                   ,"FM"		, "691"     , 7		, "011" },
	{"Moldova"                      ,"MD"		, "373"     , 8		, "00"  },
	{"Monaco"                       ,"MC"		, "377"     , 8     , "00"	},
	{"Mongolia"                     ,"MN"		, "976"     , 8     , "001" },
	{"Montenegro"                   ,"ME"		, "382"     , 8		, "00"  },
	{"Montserrat"                   ,"MS"		, "664"     , 10	, "011" },
	{"Morocco"                      ,"MA"		, "212"     , 9     , "00"	},
	{"Mozambique"                   ,"MZ"		, "258"     , 9     , "00"  },
	{"Myanmar"                      ,"MM"		, "95"      , 8		, "00"  },
	{"Namibia"                      ,"NA"		, "264"     , 9		, "00"	},
	{"Nauru"                        ,"NR"		, "674"     , 7	    , "00"  },
	{"Nepal"                        ,"NP"		, "43"      , 10	, "00"  },
	{"Netherlands"                  ,"NL"       , "31"      , 9		, "00"  },
	{"New Caledonia"				,"NC"		, "687"     , 6     , "00"	},
	{"New Zealand"                  ,"NZ"		, "64"      , 10	, "00"  },
	{"Nicaragua"                    ,"NI"		, "505"     , 8     , "00"  },
	{"Niger"                        ,"NE"		, "227"     , 8     , "00"	},
	{"Nigeria"                      ,"NG"		, "234"     , 10	, "009"	},
	{"Niue"                         ,"NU"		, "683"     , 4		, "00"	},
	{"Norfolk Island"	            ,"NF"		, "672"     , 5		, "00"  },
	{"Northern Mariana Islands"	    ,"MP"		, "1"       , 10	, "011" },
	{"Norway"                       ,"NO"		, "47"      , 8     , "00"	},
	{"Oman"                         ,"OM"		, "968"     , 8		, "00"  },
	{"Pakistan"                     ,"PK"		, "92"      , 10	, "00"  },
	{"Palau"                        ,"PW"		, "680"     , 7     , "011" },
	{"Palestine"                    ,"PS"		, "970"     , 9     , "00"	},
	{"Panama"                       ,"PA"		, "507"     , 8     , "00"  },
	{"Papua New Guinea"	            ,"PG"		, "675"     , 8		, "00"  },
	{"Paraguay"                     ,"PY"		, "595"     , 9		, "00"	},
	{"Peru"                         ,"PE"		, "51"      , 9	    , "00"  },
	{"Philippines"                  ,"PH"		, "63"      , 10	, "00"  },
	{"Poland"                       ,"PL"       , "48"      , 9		, "00"  },
	{"Portugal"                     ,"PT"		, "351"     , 9     , "00"	},
	{"Puerto Rico"                  ,"PR"		, "1"       , 10	, "011" },
	{"Qatar"                        ,"QA"		, "974"     , 8     , "00"  },
	{"R�union Island"				,"RE"		, "262"     , 9     , "011"	},
	{"Romania"                      ,"RO"		, "40"      , 9     , "00"	},
	{"Russian Federation"           ,"RU"		, "7"       , 10	, "8"	},
	{"Rwanda"                       ,"RW"		, "250"     , 9		, "00"  },
	{"Saint Helena"                 ,"SH"		, "290"     , 4		, "00"  },
	{"Saint Kitts and Nevis"		,"KN"		, "1"       , 10	, "011"	},
	{"Saint Lucia"                  ,"LC"		, "1"       , 10	, "011" },
	{"Saint Pierre and Miquelon"    ,"PM"		, "508"     , 6		, "00"  },
	{"Saint Vincent and the Grenadines","VC"	, "1"       , 10	, "011" },
	{"Samoa"                        ,"WS"		, "685"     , 7     , "0"	},
	{"San Marino"                   ,"SM"		, "378"     , 10	, "00"  },
785
	{"Sao Tome and Principe"        ,"ST"		, "239"     , 7		, "00"  },
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
	{"Saudi Arabia"                 ,"SA"		, "966"     , 9		, "00"	},
	{"Senegal"                      ,"SN"		, "221"     , 9	    , "00"  },
	{"Serbia"                       ,"RS"		, "381"     , 9     , "00"  },
	{"Seychelles"                   ,"SC"       , "248"     , 7		, "00"  },
	{"Sierra Leone"                 ,"SL"		, "232"     , 8     , "00"	},
	{"Singapore"                    ,"SG"		, "65"      , 8     , "001" },
	{"Slovakia"                     ,"SK"		, "421"     , 9     , "00"  },
	{"Slovenia"                     ,"SI"		, "386"     , 8     , "00"	},
	{"Solomon Islands"              ,"SB"		, "677"     , 7     , "00"	},
	{"Somalia"                      ,"SO"		, "252"     , 8		, "00"	},
	{"South Africa"                 ,"ZA"		, "27"      , 9		, "00"  },
	{"Spain"                        ,"ES"		, "34"      , 9		, "00"  },
	{"Sri Lanka"                    ,"LK"		, "94"      , 9     , "00"	},
	{"Sudan"                        ,"SD"		, "249"     , 9		, "00"  },
	{"Suriname"                     ,"SR"		, "597"     , 7		, "00"  },
	{"Swaziland"                    ,"SZ"		, "268"     , 8     , "00"  },
	{"Sweden"                       ,"SE"		, "1"       , 9     , "00"	},
	{"Switzerland"                  ,"XK"		, "41"      , 9		, "00"	},
	{"Syria"                        ,"SY"		, "963"     , 9		, "00"  },
	{"Taiwan"                       ,"TW"		, "886"     , 9		, "810"	},
	{"Tajikistan"                   ,"TJ"		, "992"     , 9	    , "002" },
	{"Tanzania"                     ,"TZ"		, "255"     , 9     , "000" },
	{"Thailand"                     ,"TH"       , "66"      , 9		, "001" },
	{"Togo"                         ,"TG"		, "228"     , 8     , "00"	},
	{"Tokelau"                      ,"TK"		, "690"     , 4     , "00"  },
	{"Tonga"                        ,"TO"		, "676"     , 5     , "00"  },
	{"Trinidad and Tobago"			,"TT"		, "1"       , 10    , "011"	},
	{"Tunisia"                      ,"TN"		, "216"     , 8     , "00"	},
	{"Turkey"                       ,"TR"		, "90"      , 10	, "00"	},
	{"Turkmenistan"                 ,"TM"		, "993"     , 8		, "00"  },
	{"Turks and Caicos Islands"	    ,"TC"		, "1"       , 7		, "0"   },
	{"Tuvalu"                       ,"TV"		, "688"     , 5     , "00"	},
	{"Uganda"                       ,"UG"		, "256"     , 9     , "000" },
	{"Ukraine"                      ,"UA"		, "380"     , 9		, "00"  },
	{"United Arab Emirates"	        ,"AE"		, "971"     , 9     , "00"  },
	{"United Kingdom"               ,"UK"		, "44"      , 10	, "00"	},
	{"United States"                ,"US"		, "1"       , 10	, "011" },
	{"Uruguay"                      ,"UY"		, "598"     , 8		, "00"  },
	{"Uzbekistan"                   ,"UZ"		, "998"     , 9		, "8"	},
	{"Vanuatu"                      ,"VU"		, "678"     , 7	    , "00"  },
	{"Venezuela"                    ,"VE"		, "58"      , 10	, "00"  },
	{"Vietnam"                      ,"VN"		, "84"      , 9     , "00"  },
	{"Wallis and Futuna"	        ,"WF"		, "681"     , 5		, "00"  },
	{"Yemen"                        ,"YE"		, "967"     , 9     , "00"  },
	{"Zambia"                       ,"ZM"		, "260"     , 9     , "00"	},
	{"Zimbabwe"                     ,"ZW"		, "263"     , 9     , "00"  },
jehan's avatar
jehan committed
832
	{NULL                           ,NULL       ,  ""       , 0     , NULL	}
833
};
834 835
static dial_plan_t most_common_dialplan={ "generic" ,"", "", 10, "00"};

836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
int linphone_dial_plan_lookup_ccc_from_e164(const char* e164) {
	dial_plan_t* dial_plan;
	dial_plan_t* elected_dial_plan=NULL;
	unsigned int found;
	unsigned int i=0;
	if (e164[1]=='1') {
		/*USA case*/
		return 1;
	}
	do {
		found=0;
		i++;
		for (dial_plan=(dial_plan_t*)dial_plans; dial_plan->country!=NULL; dial_plan++) {
			if (strncmp(dial_plan->ccc,&e164[1],i) == 0) {
				elected_dial_plan=dial_plan;
				found++;
			}
		}
854
	} while ((found>1 || found==0) && i < sizeof(dial_plan->ccc));
855 856 857 858 859 860 861
	if (found==1) {
		return atoi(elected_dial_plan->ccc);
	} else {
		return -1; /*not found */
	}

}
862 863 864 865 866 867 868 869 870
int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) {
	dial_plan_t* dial_plan;
	for (dial_plan=(dial_plan_t*)dial_plans; dial_plan->country!=NULL; dial_plan++) {
		if (strcmp(iso, dial_plan->iso_country_code)==0) {
			return atoi(dial_plan->ccc);
		}
	}
	return -1;
}
871

872
static bool_t lookup_dial_plan_by_ccc(const char *ccc, dial_plan_t *plan){
873 874 875 876
	int i;
	for(i=0;dial_plans[i].country!=NULL;++i){
		if (strcmp(ccc,dial_plans[i].ccc)==0){
			*plan=dial_plans[i];
877
			return TRUE;
878 879 880 881 882
		}
	}
	/*else return a generic "most common" dial plan*/
	*plan=most_common_dialplan;
	strcpy(plan->ccc,ccc);
883
	return FALSE;
884
}
885

886
bool_t linphone_proxy_config_is_phone_number(LinphoneProxyConfig *proxy, const char *username){
887 888
	const char *p;
	for(p=username;*p!='\0';++p){
889
		if (isdigit(*p) ||
890
		    *p==' ' ||
891
		    *p=='.' ||
892 893 894 895
		    *p=='-' ||
		    *p==')' ||
			*p=='(' ||
			*p=='/' ||
896 897 898 899 900
			*p=='+' ||
			(unsigned char)*p== 0xca // non-breakable space (iOS uses it to format contacts phone number)
			)
			continue;
		return FALSE;
901 902 903 904
	}
	return TRUE;
}

905
//remove anything but [0-9] and +
906 907 908 909 910 911 912 913 914 915 916 917 918
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){
		if (*r=='+' || isdigit(*r)){
			*w++=*r;
		}
	}
	*w++='\0';
	return result;
}

919
static void replace_plus_with_icp(const char *src, char *dest, size_t destlen, const char *icp){
920
	int i=0;
921

922
	if (icp && src[0]=='+' && (destlen>(i=strlen(icp))) ){
923
		src++;
924
		strncpy(dest, icp, destlen);
925
	}
926

Simon Morlat's avatar
Simon Morlat committed
927
	for(;(i<destlen-1) && *src!='\0';++i){
928 929 930 931 932 933
		dest[i]=*src;
		src++;
	}
	dest[i]='\0';
}

934
static void replace_icp_with_plus(const char *src, char *dest, size_t destlen, const char *icp){
935 936 937 938 939 940 941 942
	int i=0;
	if (strstr(src, icp) == src){
		dest[0]='+';
		i++;
	}
	strncpy(dest+i, src+strlen(icp), destlen-i-1);
}

943

944 945 946
bool_t linphone_proxy_config_normalize_number(LinphoneProxyConfig *inproxy, const char *username, char *result, size_t result_len){
	bool_t ret;
	LinphoneProxyConfig *proxy = inproxy ? inproxy : linphone_proxy_config_new();
947
	memset(result, 0, result_len);
948
	if (linphone_proxy_config_is_phone_number(proxy, username)){
949
		dial_plan_t dialplan = {0};
950
		char *flatten=flatten_number(username);
951
		ms_debug("Flattened number is '%s'",flatten);
952