account_creator.c 49.7 KB
Newer Older
1 2
/*
linphone
3
Copyright (C) 2010-2017 Belledonne Communications SARL
4 5 6 7 8 9 10 11 12 13 14 15 16

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 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
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 19
*/

20
#include "linphone/account_creator.h"
21
#include "linphone/core.h"
22
#include "linphone/lpconfig.h"
23
#include "private.h"
24
#if !_WIN32
25
#include "regex.h"
26
#endif
27

28 29
#include <bctoolbox/crypto.h>

30
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneAccountCreatorCbs);
31

32
BELLE_SIP_INSTANCIATE_VPTR(LinphoneAccountCreatorCbs, belle_sip_object_t,
33 34 35 36 37 38 39
	NULL, // destroy
	NULL, // clone
	NULL, // marshal
	FALSE
);

/************************** Start Misc **************************/
40 41 42 43 44 45
static const char* ha1_for_passwd(const char* username, const char* realm, const char* passwd) {
	static char ha1[33];
	sal_auth_compute_ha1(username, realm, passwd, ha1);
	return ha1;
}

Erwan Croze's avatar
Erwan Croze committed
46
static unsigned int validate_uri(const char* username, const char* domain, const char* display_name) {
47
	LinphoneAddress* addr;
Erwan Croze's avatar
Erwan Croze committed
48 49 50
	int status = 0;
	LinphoneProxyConfig* proxy = linphone_proxy_config_new();
	linphone_proxy_config_set_identity(proxy, "sip:userame@domain.com");
51 52 53 54 55 56 57

	if (username) {
		addr = linphone_proxy_config_normalize_sip_uri(proxy, username);
	} else {
		addr = linphone_address_clone(linphone_proxy_config_get_identity_address(proxy));
	}

Erwan Croze's avatar
Erwan Croze committed
58 59 60 61
	if (addr == NULL) {
		status = 1;
		goto end;
	}
62

Erwan Croze's avatar
Erwan Croze committed
63 64
	if (domain && linphone_address_set_domain(addr, domain) != 0) {
		status = 1;
65 66
	}

Erwan Croze's avatar
Erwan Croze committed
67 68 69
	if (display_name && (!strlen(display_name) || linphone_address_set_display_name(addr, display_name) != 0)) {
		status = 1;
	}
70
	linphone_address_unref(addr);
Erwan Croze's avatar
Erwan Croze committed
71 72 73
end:
	linphone_proxy_config_destroy(proxy);
	return status;
74 75 76 77 78 79 80 81 82 83
}

static char* _get_identity(const LinphoneAccountCreator *creator) {
	char *identity = NULL;
	if ((creator->username || creator->phone_number)) {
		//we must escape username
		LinphoneProxyConfig* proxy = creator->proxy_cfg;
		LinphoneAddress* addr;

		addr = linphone_proxy_config_normalize_sip_uri(proxy, creator->username ? creator->username : creator->phone_number);
Erwan Croze's avatar
Erwan Croze committed
84
		if (addr == NULL) return NULL;
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110

		identity = linphone_address_as_string(addr);
		linphone_address_unref(addr);
	}
	return identity;
}

static bool_t is_matching_regex(const char *entry, const char* regex) {
#if _WIN32
	return TRUE;
#else
	regex_t regex_pattern;
	char err_msg[256];
	int res;
	res = regcomp(&regex_pattern, regex, REG_EXTENDED | REG_NOSUB);
	if(res != 0) {
		regerror(res, &regex_pattern, err_msg, sizeof(err_msg));
		ms_error("Could not compile regex '%s: %s", regex, err_msg);
		return FALSE;
	}
	res = regexec(&regex_pattern, entry, 0, NULL, 0);
	regfree(&regex_pattern);
	return (res != REG_NOMATCH);
#endif
}

111
LinphoneProxyConfig * linphone_account_creator_create_proxy_config(const LinphoneAccountCreator *creator) {
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
	LinphoneAuthInfo *info;
	LinphoneProxyConfig *cfg = linphone_core_create_proxy_config(creator->core);
	char *identity_str = _get_identity(creator);
	LinphoneAddress *identity = linphone_address_new(identity_str);
	ms_free(identity_str);

	linphone_proxy_config_set_identity_address(cfg, identity);
	if (creator->phone_country_code) {
		linphone_proxy_config_set_dial_prefix(cfg, creator->phone_country_code);
	} else if (creator->phone_number) {
		int dial_prefix_number = linphone_dial_plan_lookup_ccc_from_e164(creator->phone_number);
		char buff[4];
		snprintf(buff, sizeof(buff), "%d", dial_prefix_number);
		linphone_proxy_config_set_dial_prefix(cfg, buff);
	}

	info = linphone_auth_info_new(linphone_address_get_username(identity), // username
								NULL, //user id
								creator->password, // passwd
								creator->password ? NULL : creator->ha1,  // ha1
								!creator->password && creator->ha1 ? linphone_address_get_domain(identity) : NULL,  // realm - assumed to be domain
								linphone_address_get_domain(identity) // domain
	);
	linphone_core_add_auth_info(creator->core, info);
	linphone_address_unref(identity);

	if (linphone_core_add_proxy_config(creator->core, cfg) != -1) {
		linphone_core_set_default_proxy(creator->core, cfg);
		return cfg;
	}

	linphone_core_remove_auth_info(creator->core, info);
	return NULL;
}

147 148 149 150 151
LinphoneProxyConfig * linphone_account_creator_configure(const LinphoneAccountCreator *creator) {
	LinphoneAuthInfo *info;
	LinphoneProxyConfig *cfg = creator->proxy_cfg;
	char *identity_str = _get_identity(creator);
	LinphoneAddress *identity = linphone_address_new(identity_str);
Erwan Croze's avatar
Erwan Croze committed
152 153
	char *route = NULL;
	char *domain = NULL;
154 155 156 157
	ms_free(identity_str);
	if (creator->display_name) {
		linphone_address_set_display_name(identity, creator->display_name);
	}
Erwan Croze's avatar
Erwan Croze committed
158 159 160 161 162 163
	if (creator->route) {
		route = ms_strdup_printf("%s", creator->route);
	}
	if (creator->domain) {
		domain = ms_strdup_printf("%s", creator->domain);
	}
164 165 166 167 168 169 170 171 172
	linphone_proxy_config_set_identity_address(cfg, identity);
	if (creator->phone_country_code) {
		linphone_proxy_config_set_dial_prefix(cfg, creator->phone_country_code);
	} else if (creator->phone_number) {
		int dial_prefix_number = linphone_dial_plan_lookup_ccc_from_e164(creator->phone_number);
		char buff[4];
		snprintf(buff, sizeof(buff), "%d", dial_prefix_number);
		linphone_proxy_config_set_dial_prefix(cfg, buff);
	}
Erwan Croze's avatar
Erwan Croze committed
173 174 175 176 177
	if (linphone_proxy_config_get_server_addr(cfg) == NULL)
		linphone_proxy_config_set_server_addr(cfg, domain);
	if (linphone_proxy_config_get_route(cfg) == NULL)
		linphone_proxy_config_set_route(cfg, route);

178 179 180
	linphone_proxy_config_enable_publish(cfg, FALSE);
	linphone_proxy_config_enable_register(cfg, TRUE);

Erwan Croze's avatar
Erwan Croze committed
181 182
	if (linphone_proxy_config_get_realm(cfg) != NULL
		&& strcmp(linphone_proxy_config_get_realm(cfg), "sip.linphone.org") == 0) {
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
		linphone_proxy_config_enable_avpf(cfg, TRUE);
		// If account created on sip.linphone.org, we configure linphone to use TLS by default
		if (linphone_core_sip_transport_supported(creator->core, LinphoneTransportTls)) {
			LinphoneAddress *addr = linphone_address_new(linphone_proxy_config_get_server_addr(cfg));
			char *tmp;
			linphone_address_set_transport(addr, LinphoneTransportTls);
			tmp = linphone_address_as_string(addr);
			linphone_proxy_config_set_server_addr(cfg, tmp);
			linphone_proxy_config_set_route(cfg, tmp);
			ms_free(tmp);
			linphone_address_unref(addr);
		}
		linphone_core_set_stun_server(creator->core, "stun.linphone.org");
		linphone_core_set_firewall_policy(creator->core, LinphonePolicyUseIce);
	}

	info = linphone_auth_info_new(linphone_address_get_username(identity), // username
								NULL, //user id
								creator->password, // passwd
								creator->password ? NULL : creator->ha1,  // ha1
								!creator->password && creator->ha1 ? linphone_address_get_domain(identity) : NULL,  // realm - assumed to be domain
								linphone_address_get_domain(identity) // domain
	);
	linphone_core_add_auth_info(creator->core, info);
	linphone_address_unref(identity);

	if (linphone_core_add_proxy_config(creator->core, cfg) != -1) {
		linphone_core_set_default_proxy(creator->core, cfg);
		return cfg;
	}

	linphone_core_remove_auth_info(creator->core, info);
	return NULL;
}
/************************** End Misc **************************/

/************************** Start Account Creator Cbs **************************/

221 222
static LinphoneAccountCreatorCbs * linphone_account_creator_cbs_new(void) {
	return belle_sip_object_new(LinphoneAccountCreatorCbs);
223 224
}

225 226 227
LinphoneAccountCreatorCbs * linphone_account_creator_cbs_ref(LinphoneAccountCreatorCbs *cbs) {
	belle_sip_object_ref(cbs);
	return cbs;
228 229
}

230 231
void linphone_account_creator_cbs_unref(LinphoneAccountCreatorCbs *cbs) {
	belle_sip_object_unref(cbs);
232 233
}

234 235
void *linphone_account_creator_cbs_get_user_data(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->user_data;
236 237
}

238 239
void linphone_account_creator_cbs_set_user_data(LinphoneAccountCreatorCbs *cbs, void *ud) {
	cbs->user_data = ud;
240 241
}

242 243
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_create_account(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->create_account_response_cb;
244 245
}

246 247
void linphone_account_creator_cbs_set_create_account(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->create_account_response_cb = cb;
248 249
}

250 251
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_is_account_exist(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->is_account_exist_response_cb;
252 253
}

254 255
void linphone_account_creator_cbs_set_is_account_exist(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->is_account_exist_response_cb = cb;
256 257
}

258 259
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_activate_account(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->activate_account_response_cb;
260 261
}

262 263
void linphone_account_creator_cbs_set_activate_account(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->activate_account_response_cb = cb;
264 265
}

266 267
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_is_account_activated(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->is_account_activated_response_cb;
268 269
}

270 271
void linphone_account_creator_cbs_set_is_account_activated(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->is_account_activated_response_cb = cb;
272 273
}

274 275
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_link_account(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->link_account_response_cb;
276 277
}

278 279
void linphone_account_creator_cbs_set_link_account(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->link_account_response_cb = cb;
280 281
}

282 283
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_activate_alias(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->activate_alias_response_cb;
284
}
285

286 287
void linphone_account_creator_cbs_set_activate_alias(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->activate_alias_response_cb = cb;
288 289
}

290 291
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_is_alias_used(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->is_alias_used_response_cb;
292 293
}

294 295
void linphone_account_creator_cbs_set_is_alias_used(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->is_alias_used_response_cb = cb;
296 297
}

298 299
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_is_account_linked(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->is_account_linked_response_cb;
300
}
301

302 303
void linphone_account_creator_cbs_set_is_account_linked(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->is_account_linked_response_cb = cb;
304 305
}

306 307
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_recover_account(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->recover_account_response_cb;
308 309
}

310 311
void linphone_account_creator_cbs_set_recover_account(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->recover_account_response_cb = cb;
312 313
}

314 315
LinphoneAccountCreatorCbsStatusCb linphone_account_creator_cbs_get_update_account(const LinphoneAccountCreatorCbs *cbs) {
	return cbs->update_account_response_cb;
316 317
}

318 319
void linphone_account_creator_cbs_set_update_account(LinphoneAccountCreatorCbs *cbs, LinphoneAccountCreatorCbsStatusCb cb) {
	cbs->update_account_response_cb = cb;
320 321 322 323
}
/************************** End Account Creator Cbs **************************/

/************************** Start Account Creator data **************************/
324
static void _linphone_account_creator_destroy(LinphoneAccountCreator *creator) {
325 326
	/*this will drop all pending requests if any*/
	if (creator->xmlrpc_session) linphone_xml_rpc_session_release(creator->xmlrpc_session);
327 328 329
	if (creator->service != NULL && linphone_account_creator_service_get_destructor_cb(creator->service) != NULL)
		linphone_account_creator_service_get_destructor_cb(creator->service)(creator);
	linphone_account_creator_cbs_unref(creator->cbs);
330
	linphone_proxy_config_unref(creator->proxy_cfg);
331
	linphone_account_creator_reset(creator);
332 333 334 335 336 337 338 339 340 341 342
}

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneAccountCreator);

BELLE_SIP_INSTANCIATE_VPTR(LinphoneAccountCreator, belle_sip_object_t,
	(belle_sip_object_destroy_t)_linphone_account_creator_destroy,
	NULL, // clone
	NULL, // marshal
	FALSE
);

343
LinphoneAccountCreator * _linphone_account_creator_new(LinphoneCore *core, const char *xmlrpc_url) {
344
	LinphoneAccountCreator *creator;
Erwan Croze's avatar
Erwan Croze committed
345
	const char* domain = lp_config_get_string(core->config, "assistant", "domain", NULL);
346
	creator = belle_sip_object_new(LinphoneAccountCreator);
347 348
	creator->service = linphone_core_get_account_creator_service(core);
	creator->cbs = linphone_account_creator_cbs_new();
349
	creator->core = core;
350
	creator->xmlrpc_session = (xmlrpc_url) ? linphone_xml_rpc_session_new(core, xmlrpc_url) : NULL;
Erwan Croze's avatar
Erwan Croze committed
351 352 353
	if (domain) {
		linphone_account_creator_set_domain(creator, domain);
	}
354
	creator->proxy_cfg = linphone_core_create_proxy_config(core);
355 356
	if (creator->service != NULL && linphone_account_creator_service_get_constructor_cb(creator->service) != NULL)
		linphone_account_creator_service_get_constructor_cb(creator->service)(creator);
357 358 359
	return creator;
}

360 361 362 363
LinphoneAccountCreator * linphone_account_creator_new(LinphoneCore *core, const char *xmlrpc_url) {
	return _linphone_account_creator_new(core, xmlrpc_url);
}

364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
#define _reset_field(field) \
	if (field) { \
		ms_free(field); \
		field = NULL; \
	}

void linphone_account_creator_reset(LinphoneAccountCreator *creator) {
	_reset_field(creator->username);
	_reset_field(creator->display_name);
	_reset_field(creator->password);
	_reset_field(creator->ha1);
	_reset_field(creator->phone_number);
	_reset_field(creator->phone_country_code);
	_reset_field(creator->email);
	_reset_field(creator->language);
	_reset_field(creator->activation_code);
	_reset_field(creator->domain);
	_reset_field(creator->route);
}

#undef _reset_field

386 387 388 389
LinphoneAccountCreator * linphone_core_create_account_creator(LinphoneCore *core, const char *xmlrpc_url) {
	return _linphone_account_creator_new(core, xmlrpc_url);
}

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
LinphoneAccountCreator * linphone_account_creator_ref(LinphoneAccountCreator *creator) {
	belle_sip_object_ref(creator);
	return creator;
}

void linphone_account_creator_unref(LinphoneAccountCreator *creator) {
	belle_sip_object_unref(creator);
}

void *linphone_account_creator_get_user_data(const LinphoneAccountCreator *creator) {
	return creator->user_data;
}

void linphone_account_creator_set_user_data(LinphoneAccountCreator *creator, void *ud) {
	creator->user_data = ud;
}

407
LinphoneAccountCreatorUsernameStatus linphone_account_creator_set_username(LinphoneAccountCreator *creator, const char *username) {
408 409
	int min_length = lp_config_get_int(creator->core->config, "assistant", "username_min_length", -1);
	int max_length = lp_config_get_int(creator->core->config, "assistant", "username_max_length", -1);
410 411
	bool_t use_phone_number = lp_config_get_int(creator->core->config, "assistant", "use_phone_number", 0);
	const char* regex = lp_config_get_string(creator->core->config, "assistant", "username_regex", 0);
412 413
	if (!username) {
		creator->username = NULL;
414
		return LinphoneAccountCreatorUsernameStatusOk;
415
	} else if (min_length > 0 && strlen(username) < (size_t)min_length) {
416
		return LinphoneAccountCreatorUsernameStatusTooShort;
417
	} else if (max_length > 0 && strlen(username) > (size_t)max_length) {
418
		return LinphoneAccountCreatorUsernameStatusTooLong;
419
	} else if (use_phone_number && !linphone_proxy_config_is_phone_number(NULL, username)) {
420
		return LinphoneAccountCreatorUsernameStatusInvalid;
421
	} else if (regex && !is_matching_regex(username, regex)) {
422
		return LinphoneAccountCreatorUsernameStatusInvalidCharacters;
Erwan Croze's avatar
Erwan Croze committed
423
	} else if (validate_uri(username, NULL, NULL) != 0) {
424
		return LinphoneAccountCreatorUsernameStatusInvalid;
425
	}
426

427
	set_string(&creator->username, username, TRUE);
428
	return LinphoneAccountCreatorUsernameStatusOk;
429 430 431 432 433 434
}

const char * linphone_account_creator_get_username(const LinphoneAccountCreator *creator) {
	return creator->username;
}

435
LinphoneAccountCreatorPhoneNumberStatusMask linphone_account_creator_set_phone_number(LinphoneAccountCreator *creator, const char *phone_number, const char *country_code) {
436
	char *normalized_phone_number;
437
	LinphoneAccountCreatorPhoneNumberStatusMask return_status = 0;
438
	if (!phone_number || !country_code) {
439 440
		if (!phone_number && !country_code) {
			creator->phone_number = NULL;
441
			creator->phone_country_code = NULL;
442
			return (LinphoneAccountCreatorPhoneNumberStatusMask)LinphoneAccountCreatorPhoneNumberStatusOk;
443
		} else {
444
			return (LinphoneAccountCreatorPhoneNumberStatusMask)LinphoneAccountCreatorPhoneNumberStatusInvalid;
445
		}
446
	} else {
447
		LinphoneProxyConfig *numCfg = creator->proxy_cfg;
448 449
		creator->phone_country_code = ms_strdup(country_code[0] == '+' ? &country_code[1] : country_code);
		linphone_proxy_config_set_dial_prefix(numCfg, creator->phone_country_code);
450 451
		normalized_phone_number = linphone_proxy_config_normalize_phone_number(numCfg, phone_number);
		if (!normalized_phone_number) {
452
			return LinphoneAccountCreatorPhoneNumberStatusInvalid;
453 454 455 456
		}

		// if phone is valid, we lastly want to check that length is OK
		{
Erwan Croze's avatar
Erwan Croze committed
457
			const LinphoneDialPlan* plan = linphone_dial_plan_by_ccc(creator->phone_country_code);
458
			int size = (int)strlen(phone_number);
459
			if (linphone_dial_plan_is_generic(plan)) {
460
				return_status = LinphoneAccountCreatorPhoneNumberStatusInvalidCountryCode;
461
			}
462
			if (size < plan->nnl - 1) {
463
				return_status += LinphoneAccountCreatorPhoneNumberStatusTooShort;
Erwan Croze's avatar
Erwan Croze committed
464
				goto end;
465
			} else if (size > plan->nnl + 1) {
466
				return_status += LinphoneAccountCreatorPhoneNumberStatusTooLong;
467
				goto end;
468
			} else if (return_status & LinphoneAccountCreatorPhoneNumberStatusInvalidCountryCode) {
Erwan Croze's avatar
Erwan Croze committed
469
				goto end;
470 471 472
			}
		}
	}
473
	set_string(&creator->phone_number, normalized_phone_number, TRUE);
474
	return_status = LinphoneAccountCreatorPhoneNumberStatusOk;
Erwan Croze's avatar
Erwan Croze committed
475 476 477
end:
	ms_free(normalized_phone_number);
	return return_status;
478 479 480 481 482 483
}

const char * linphone_account_creator_get_phone_number(const LinphoneAccountCreator *creator) {
	return creator->phone_number;
}

484
LinphoneAccountCreatorPasswordStatus linphone_account_creator_set_password(LinphoneAccountCreator *creator, const char *password) {
485 486
	int min_length = lp_config_get_int(creator->core->config, "assistant", "password_min_length", -1);
	int max_length = lp_config_get_int(creator->core->config, "assistant", "password_max_length", -1);
487 488
	if (!password) {
		creator->password = NULL;
489
		return LinphoneAccountCreatorPasswordStatusTooShort;
490
	}
491
	if (min_length > 0 && strlen(password) < (size_t)min_length) {
492
		return LinphoneAccountCreatorPasswordStatusTooShort;
493
	} else if (max_length > 0 && strlen(password) > (size_t)max_length) {
494
		return LinphoneAccountCreatorPasswordStatusTooLong;
495
	}
496
	set_string(&creator->password, password, FALSE);
497
	return LinphoneAccountCreatorPasswordStatusOk;
498 499 500 501 502 503
}

const char * linphone_account_creator_get_password(const LinphoneAccountCreator *creator) {
	return creator->password;
}

504
LinphoneAccountCreatorPasswordStatus linphone_account_creator_set_ha1(LinphoneAccountCreator *creator, const char *ha1){
505
	set_string(&creator->ha1, ha1, FALSE);
506
	return LinphoneAccountCreatorPasswordStatusOk;
507 508 509 510 511 512
}

const char * linphone_account_creator_get_ha1(const LinphoneAccountCreator *creator) {
	return creator->ha1;
}

513
LinphoneAccountCreatorActivationCodeStatus linphone_account_creator_set_activation_code(LinphoneAccountCreator *creator, const char *activation_code){
514
	set_string(&creator->activation_code, activation_code, FALSE);
515
	return LinphoneAccountCreatorActivationCodeStatusOk;
516 517
}

518 519 520 521
const char * linphone_account_creator_get_activation_code(const LinphoneAccountCreator *creator) {
	return creator->activation_code;
}

522
LinphoneAccountCreatorLanguageStatus linphone_account_creator_set_language(LinphoneAccountCreator *creator, const char *lang) {
523
	set_string(&creator->language, lang, FALSE);
524
	return LinphoneAccountCreatorLanguageStatusOk;
525 526 527 528
}

const char * linphone_account_creator_get_language(const LinphoneAccountCreator *creator) {
	return creator->language;
529 530
}

531
LinphoneAccountCreatorUsernameStatus linphone_account_creator_set_display_name(LinphoneAccountCreator *creator, const char *display_name) {
Erwan Croze's avatar
Erwan Croze committed
532
	if (validate_uri(NULL, display_name, NULL) != 0) {
533
		return LinphoneAccountCreatorUsernameStatusInvalid;
534
	}
535
	set_string(&creator->display_name, display_name, FALSE);
536
	return LinphoneAccountCreatorUsernameStatusOk;
537 538
}

539 540
const char * linphone_account_creator_get_display_name(const LinphoneAccountCreator *creator) {
	return creator->display_name;
541 542
}

543
LinphoneAccountCreatorEmailStatus linphone_account_creator_set_email(LinphoneAccountCreator *creator, const char *email) {
544
	if (!email || !is_matching_regex(email, "^.+@.+\\..*$")) {
545
		return LinphoneAccountCreatorEmailStatusMalformed;
546 547
	}
	if (!is_matching_regex(email, "^.+@.+\\.[A-Za-z]{2}[A-Za-z]*$")) {
548
		return LinphoneAccountCreatorEmailStatusInvalidCharacters;
549
	}
550
	set_string(&creator->email, email, TRUE);
551
	return LinphoneAccountCreatorEmailStatusOk;
552 553
}

554 555
const char * linphone_account_creator_get_email(const LinphoneAccountCreator *creator) {
	return creator->email;
556 557
}

558
LinphoneAccountCreatorStatus linphone_account_creator_set_domain(LinphoneAccountCreator *creator, const char *domain) {
Erwan Croze's avatar
Erwan Croze committed
559
	if (domain && validate_uri(NULL, domain, NULL) != 0) {
560
		return LinphoneAccountCreatorStatusRequestFailed;
Erwan Croze's avatar
Erwan Croze committed
561 562 563
	}

	set_string(&creator->domain, domain, TRUE);
564
	return LinphoneAccountCreatorStatusRequestOk;
Erwan Croze's avatar
Erwan Croze committed
565 566 567 568 569 570
 }

const char * linphone_account_creator_get_domain(const LinphoneAccountCreator *creator) {
	return creator->domain;
}

571
LinphoneAccountCreatorStatus linphone_account_creator_set_route(LinphoneAccountCreator *creator, const char *route) {
Erwan Croze's avatar
Erwan Croze committed
572
	if (!route || linphone_proxy_config_set_route(creator->proxy_cfg, route) != 0)
573
		return LinphoneAccountCreatorStatusRequestFailed;
Erwan Croze's avatar
Erwan Croze committed
574 575

	set_string(&creator->route, route, TRUE);
576
	return LinphoneAccountCreatorStatusRequestOk;
Erwan Croze's avatar
Erwan Croze committed
577 578 579 580 581 582
}

const char * linphone_account_creator_get_route(const LinphoneAccountCreator *creator) {
	return creator->route;
}

583 584
LinphoneAccountCreatorCbs * linphone_account_creator_get_callbacks(const LinphoneAccountCreator *creator) {
	return creator->cbs;
585 586
}

587 588
LinphoneAccountCreatorService * linphone_account_creator_get_service(const LinphoneAccountCreator *creator) {
	return creator->service;
589 590
}

591 592 593 594
LinphoneAccountCreatorStatus linphone_account_creator_is_account_exist(LinphoneAccountCreator *creator) {
	if (creator->service->is_account_exist_request_cb == NULL
		|| creator->cbs->is_account_exist_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
595
	}
596

597
	return creator->service->is_account_exist_request_cb(creator);
598 599
}

600 601 602 603
LinphoneAccountCreatorStatus linphone_account_creator_create_account(LinphoneAccountCreator *creator) {
	if (creator->service->create_account_request_cb == NULL
		|| creator->cbs->create_account_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
604
	}
605

606
	return creator->service->create_account_request_cb(creator);
607 608
}

609 610 611 612
LinphoneAccountCreatorStatus linphone_account_creator_is_account_activated(LinphoneAccountCreator *creator) {
	if (creator->service->is_account_activated_request_cb == NULL
		|| creator->cbs->is_account_activated_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
613 614
	}

615
	return creator->service->is_account_activated_request_cb(creator);
616 617
}

618 619 620 621
LinphoneAccountCreatorStatus linphone_account_creator_activate_account(LinphoneAccountCreator *creator) {
	if (creator->service->activate_account_request_cb == NULL
		|| creator->cbs->activate_account_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
622 623
	}

624
	return creator->service->activate_account_request_cb(creator);
625 626
}

627 628 629 630
LinphoneAccountCreatorStatus linphone_account_creator_link_account(LinphoneAccountCreator *creator) {
	if (creator->service->link_account_request_cb == NULL
		|| creator->cbs->link_account_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
631
	}
632

633
	return creator->service->link_account_request_cb(creator);
634 635
}

636 637 638 639
LinphoneAccountCreatorStatus linphone_account_creator_activate_alias(LinphoneAccountCreator *creator) {
	if (creator->service->activate_alias_request_cb == NULL
		|| creator->cbs->activate_alias_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
640
	}
641

642
	return creator->service->activate_alias_request_cb(creator);
643 644
}

645 646 647 648
LinphoneAccountCreatorStatus linphone_account_creator_is_alias_used(LinphoneAccountCreator *creator) {
	if (creator->service->is_alias_used_request_cb == NULL
		|| creator->cbs->is_alias_used_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
649
	}
650

651
	return creator->service->is_alias_used_request_cb(creator);
652 653
}

654 655 656 657
LinphoneAccountCreatorStatus linphone_account_creator_is_account_linked(LinphoneAccountCreator *creator) {
	if (creator->service->is_account_linked_request_cb == NULL
		|| creator->cbs->is_account_linked_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
658
	}
659

660
	return creator->service->is_account_linked_request_cb(creator);
661 662
}

663 664 665 666
LinphoneAccountCreatorStatus linphone_account_creator_recover_account(LinphoneAccountCreator *creator) {
	if (creator->service->recover_account_request_cb == NULL
		|| creator->cbs->recover_account_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
667 668
	}

669
	return creator->service->recover_account_request_cb(creator);
670
}
671

672 673 674 675
LinphoneAccountCreatorStatus linphone_account_creator_update_account(LinphoneAccountCreator *creator) {
	if (creator->service->update_account_request_cb == NULL
		|| creator->cbs->update_account_response_cb == NULL) {
		return LinphoneAccountCreatorStatusMissingCallbacks;
676 677
	}

678
	return creator->service->update_account_request_cb(creator);
679
}
680 681 682
/************************** End Account Creator data **************************/

/************************** Start Account Creator Linphone **************************/
683

684
LinphoneAccountCreatorStatus linphone_account_creator_constructor_linphone(LinphoneAccountCreator *creator) {
685
	LinphoneAddress *addr;
686 687 688 689 690 691 692 693
	const char *identity = lp_config_get_default_string(creator->core->config, "proxy", "reg_identity", NULL);
	const char *proxy = lp_config_get_default_string(creator->core->config, "proxy", "reg_proxy", NULL);
	const char *route = lp_config_get_default_string(creator->core->config, "proxy", "reg_route", NULL);
	const char *realm = lp_config_get_default_string(creator->core->config, "proxy", "realm", NULL);
	linphone_proxy_config_set_realm(creator->proxy_cfg, realm ? realm : "sip.linphone.org");
	linphone_proxy_config_set_route(creator->proxy_cfg, route ? route : "sip.linphone.org");
	linphone_proxy_config_set_server_addr(creator->proxy_cfg, proxy ? proxy : "sip.linphone.org");
	addr = linphone_address_new(identity ? identity : "sip:username@sip.linphone.org");
694 695
	linphone_proxy_config_set_identity_address(creator->proxy_cfg, addr);
	linphone_address_unref(addr);
696
	return LinphoneAccountCreatorStatusRequestOk;
Erwan Croze's avatar
Erwan Croze committed
697 698
}

699
/****************** START OF ACCOUNT USED SECTION *****************************/
700
static void _is_account_exist_response_cb(LinphoneXmlRpcRequest *request) {
701
	LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request);
702 703
	if (creator->cbs->is_account_exist_response_cb != NULL) {
		LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed;
704
		const char* resp = linphone_xml_rpc_request_get_string_response(request);
705
		if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
706 707 708 709
			status = (strcmp(resp, "ERROR_ACCOUNT_DOESNT_EXIST") == 0) ? LinphoneAccountCreatorStatusAccountNotExist : (
							(strcmp(resp, "ERROR_ALIAS_DOESNT_EXIST") == 0) ? LinphoneAccountCreatorStatusAccountExist :
														LinphoneAccountCreatorStatusAccountExistWithAlias);
			if (status == LinphoneAccountCreatorStatusAccountExistWithAlias) {
710 711
				set_string(&creator->phone_number, resp, FALSE);
			}
712
		}
713
		creator->cbs->is_account_exist_response_cb(creator, status, resp);
714 715 716
	}
}

717
LinphoneAccountCreatorStatus linphone_account_creator_is_account_exist_linphone(LinphoneAccountCreator *creator) {
718
	LinphoneXmlRpcRequest *request;
719
	if (!creator->username && !creator->phone_number) {
720 721
		if (creator->cbs->is_account_exist_response_cb != NULL) {
			creator->cbs->is_account_exist_response_cb(creator, LinphoneAccountCreatorStatusMissingArguments, "Missing required parameters");
722
		}
723
		return LinphoneAccountCreatorStatusMissingArguments;
724
	}
725

726
	request = linphone_xml_rpc_request_new_with_args(LinphoneXmlRpcArgString, "get_phone_number_for_account",
727
		LinphoneXmlRpcArgString, creator->username ? creator->username : creator->phone_number,
728
		LinphoneXmlRpcArgString, linphone_proxy_config_get_domain(creator->proxy_cfg),
729 730
		LinphoneXmlRpcArgNone);

731
	linphone_xml_rpc_request_set_user_data(request, creator);
732
	linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _is_account_exist_response_cb);
733 734
	linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request);
	linphone_xml_rpc_request_unref(request);
735

736
	return LinphoneAccountCreatorStatusRequestOk;
737
}
738
/****************** END OF CREATE ACCOUNT USED SECTION ************************/
739

740
/****************** START OF CREATE ACCOUNT SECTION ***************************/
741
static void _create_account_cb_custom(LinphoneXmlRpcRequest *request) {
742
	LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request);
743 744
	if (creator->cbs->create_account_response_cb != NULL) {
		LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed;
745
		const char* resp = linphone_xml_rpc_request_get_string_response(request);
746
		if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
747 748 749 750 751
			status = (strcmp(resp, "OK") == 0) ? LinphoneAccountCreatorStatusAccountCreated
			: (strcmp(resp, "ERROR_CANNOT_SEND_SMS") == 0) ? LinphoneAccountCreatorStatusServerError
			: (strcmp(resp, "ERROR_ACCOUNT_ALREADY_IN_USE") == 0) ? LinphoneAccountCreatorStatusAccountExist
			: (strcmp(resp, "ERROR_ALIAS_ALREADY_IN_USE") == 0) ? LinphoneAccountCreatorStatusAccountExistWithAlias
			:LinphoneAccountCreatorStatusAccountNotCreated;
752
		}
753
		creator->cbs->create_account_response_cb(creator, status, resp);
754 755 756
	}
}

757
static LinphoneXmlRpcRequest * _create_account_with_phone_custom(LinphoneAccountCreator *creator) {
758 759 760
	LinphoneXmlRpcRequest *request;
	if (!creator->phone_number) {
		return NULL;
761
	}
762
	request = linphone_xml_rpc_request_new_with_args(LinphoneXmlRpcArgString, "create_phone_account",
763 764
		LinphoneXmlRpcArgString, creator->phone_number,
		LinphoneXmlRpcArgString, creator->username ? creator->username : creator->phone_number,
765
		LinphoneXmlRpcArgString, creator->password ? ha1_for_passwd(creator->username ? creator->username : creator->phone_number, linphone_proxy_config_get_domain(creator->proxy_cfg), creator->password) : "",
766
		LinphoneXmlRpcArgString, linphone_core_get_user_agent(creator->core),
767
		LinphoneXmlRpcArgString, linphone_proxy_config_get_domain(creator->proxy_cfg),
768
		LinphoneXmlRpcArgString, creator->language,
769 770
		LinphoneXmlRpcArgNone);
	return request;
771 772
}

773
static LinphoneXmlRpcRequest * _create_account_with_email_custom(LinphoneAccountCreator *creator) {
774
	LinphoneXmlRpcRequest *request;
775
	if (!creator->username || !creator->email || !creator->password) {
776 777
		return NULL;
	}
778
	request = linphone_xml_rpc_request_new_with_args(LinphoneXmlRpcArgString, "create_email_account",
779 780
		LinphoneXmlRpcArgString, creator->username,
		LinphoneXmlRpcArgString, creator->email,
781
		LinphoneXmlRpcArgString, ha1_for_passwd(creator->username ? creator->username : creator->phone_number, linphone_proxy_config_get_domain(creator->proxy_cfg), creator->password),
782
		LinphoneXmlRpcArgString, linphone_core_get_user_agent(creator->core),
783
		LinphoneXmlRpcArgString, linphone_proxy_config_get_domain(creator->proxy_cfg),
784 785
		LinphoneXmlRpcArgNone);
	return request;
786 787
}

788
LinphoneAccountCreatorStatus linphone_account_creator_create_account_linphone(LinphoneAccountCreator *creator) {
789
	LinphoneXmlRpcRequest *request;
790
	char *identity = _get_identity(creator);
791 792
	if (!identity || (!(request = _create_account_with_phone_custom(creator))
		&& !(request = _create_account_with_email_custom(creator)))) {
793 794
		if (creator->cbs->create_account_response_cb != NULL) {
			creator->cbs->create_account_response_cb(creator, LinphoneAccountCreatorStatusMissingArguments, "Missing required parameters");
795
		}
796
		if (identity) ms_free(identity);
797
		return LinphoneAccountCreatorStatusMissingArguments;
798
	}
799

800
	linphone_xml_rpc_request_set_user_data(request, creator);
801
	linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _create_account_cb_custom);
802 803 804
	linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request);
	linphone_xml_rpc_request_unref(request);
	ms_free(identity);
805
	return LinphoneAccountCreatorStatusRequestOk;
806
}
807
/****************** END OF CREATE ACCOUNT SECTION *****************************/
808

809
/****************** START OF VALIDATE ACCOUNT SECTION *************************/
810
static void _activate_account_cb_custom(LinphoneXmlRpcRequest *request) {
811
	LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request);
812 813
	if (creator->cbs->activate_account_response_cb != NULL) {
		LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed;
814
		const char* resp = linphone_xml_rpc_request_get_string_response(request);
815
		if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
816
			if (strcmp(resp, "ERROR_ACCOUNT_ALREADY_ACTIVATED") == 0) {
817
				status = LinphoneAccountCreatorStatusAccountAlreadyActivated;
818
			} else if (strstr(resp, "ERROR_") == resp) {
819
				status = LinphoneAccountCreatorStatusAccountNotActivated;
820
			} else {
821
				status = LinphoneAccountCreatorStatusAccountActivated;
822 823
				set_string(&creator->ha1, resp, FALSE);
			}
824
		}
825
		creator->cbs->activate_account_response_cb(creator, status, resp);
826 827 828
	}
}

829
LinphoneAccountCreatorStatus linphone_account_creator_activate_account_linphone(LinphoneAccountCreator *creator) {
830
	LinphoneXmlRpcRequest *request;
831
	if (!creator->phone_number || !creator->activation_code) {
832 833
		if (creator->cbs->is_account_activated_response_cb != NULL) {
			creator->cbs->is_account_activated_response_cb(creator, LinphoneAccountCreatorStatusMissingArguments, "Missing required parameters");
834
		}
835
		return LinphoneAccountCreatorStatusMissingArguments;
836
	}
837

838 839 840 841 842 843 844
	request = linphone_xml_rpc_request_new_with_args(LinphoneXmlRpcArgString, "activate_phone_account",
		LinphoneXmlRpcArgString, creator->phone_number,
		LinphoneXmlRpcArgString, creator->username ? creator->username : creator->phone_number,
		LinphoneXmlRpcArgString, creator->activation_code,
		linphone_proxy_config_get_domain(creator->proxy_cfg),
		LinphoneXmlRpcArgNone);

845
	linphone_xml_rpc_request_set_user_data(request, creator);
846
	linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _activate_account_cb_custom);
847 848
	linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request);
	linphone_xml_rpc_request_unref(request);
849
	return LinphoneAccountCreatorStatusRequestOk;
850
}
851
/****************** END OF CREATE VALIDATE ACCOUNT SECTION ********************/
852

853
/****************** START OF ACCOUNT VALIDATED SECTION ************************/
854
static void _is_account_activated_cb_custom(LinphoneXmlRpcRequest *request) {
855
	LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request);
856 857
	if (creator->cbs->is_account_activated_response_cb != NULL) {
		LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed;
858
		const char* resp = linphone_xml_rpc_request_get_string_response(request);
859
		if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
860
			status = (strcmp(resp, "OK") == 0) ? LinphoneAccountCreatorStatusAccountActivated : LinphoneAccountCreatorStatusAccountNotActivated;
861
		}
862
		creator->cbs->is_account_activated_response_cb(creator, status, resp);
863
	}
864 865
}

866
LinphoneAccountCreatorStatus linphone_account_creator_is_account_activated_linphone(LinphoneAccountCreator *creator) {
867 868 869
	LinphoneXmlRpcRequest *request;
	char *identity = _get_identity(creator);
	if (!identity) {
870 871
		if (creator->cbs->is_account_activated_response_cb != NULL) {
			creator->cbs->is_account_activated_response_cb(creator, LinphoneAccountCreatorStatusMissingArguments, "Missing required parameters");
872
		}
873
		return LinphoneAccountCreatorStatusMissingArguments;
874
	}
875
	request = linphone_xml_rpc_request_new_with_args(LinphoneXmlRpcArgString, "is_account_activated",
876
		LinphoneXmlRpcArgString, creator->username ? creator->username : creator->phone_number,
877
		LinphoneXmlRpcArgString, linphone_proxy_config_get_domain(creator->proxy_cfg),
878 879
		LinphoneXmlRpcArgNone);
	linphone_xml_rpc_request_set_user_data(request, creator);
880
	linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _is_account_activated_cb_custom);
881 882 883
	linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request);
	linphone_xml_rpc_request_unref(request);
	ms_free(identity);
884
	return LinphoneAccountCreatorStatusRequestOk;
885 886
}
/****************** END OF CREATE ACCOUNT VALIDATED SECTION********************/
887

888 889
/****************** START OF PHONE NUMBER VALIDATED SECTION *******************/

890
static void _is_phone_number_used_cb_custom(LinphoneXmlRpcRequest *request) {
891
	LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request);
892 893
	if (creator->cbs->is_alias_used_response_cb != NULL) {
		LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed;
894 895
		const char* resp = linphone_xml_rpc_request_get_string_response(request);
		if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
896 897 898
			status = (strcmp(resp, "OK_ACCOUNT") == 0) ? LinphoneAccountCreatorStatusAliasIsAccount
			: (strcmp(resp, "OK_ALIAS") == 0) ? LinphoneAccountCreatorStatusAliasExist
			: LinphoneAccountCreatorStatusAliasNotExist;
899
		}
900
		creator->cbs->is_alias_used_response_cb(creator, status, resp);
901 902 903
	}
}

904
LinphoneAccountCreatorStatus linphone_account_creator_is_phone_number_used_linphone(LinphoneAccountCreator *creator) {
905 906 907
	LinphoneXmlRpcRequest *request;
	char *identity = _get_identity(creator);
	if (!identity) {
908 909
		if (creator->cbs->is_alias_used_response_cb != NULL) {
			creator->cbs->is_alias_used_response_cb(creator, LinphoneAccountCreatorStatusMissingArguments, "Missing required parameters");
910
		}
911
		return LinphoneAccountCreatorStatusMissingArguments;
912
	}
913
	request = linphone_xml_rpc_request_new_with_args(LinphoneXmlRpcArgString, "is_phone_number_used",
Erwan Croze's avatar
Erwan Croze committed
914
		LinphoneXmlRpcArgString, creator->phone_number,
915
		LinphoneXmlRpcArgString, linphone_proxy_config_get_domain(creator->proxy_cfg),
916 917
		LinphoneXmlRpcArgNone);
	linphone_xml_rpc_request_set_user_data(request, creator);
918
	linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _is_phone_number_used_cb_custom);
919 920 921
	linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request);
	linphone_xml_rpc_request_unref(request);
	ms_free(identity);
922
	return LinphoneAccountCreatorStatusRequestOk;
923 924 925 926
}

/****************** END OF PHONE NUMBER VALIDATED SECTION *********************/

927
/****************** START OF LINK PHONE NUMBER WITH ACCOUNT SECTION ***********/
928
static void _link_phone_number_with_account_cb_custom(LinphoneXmlRpcRequest *request) {
929
	LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request);
930 931
	if (creator->cbs->link_account_response_cb != NULL) {
		LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed;
932
		const char* resp = linphone_xml_rpc_request_get_string_response(request);
933
		if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
934
			status = (strcmp(resp, "OK") == 0) ? LinphoneAccountCreatorStatusRequestOk : LinphoneAccountCreatorStatusAccountNotLinked;
935
		}
936
		creator->cbs->link_account_response_cb(creator, status, resp);
937
	}
938
}
939

940
LinphoneAccountCreatorStatus linphone_account_creator_link_phone_number_with_account_linphone(LinphoneAccountCreator *creator) {
941 942
	LinphoneXmlRpcRequest *request;
	if (!creator->phone_number || !creator->username) {
943 944
		if (creator->cbs->link_account_response_cb != NULL) {
			creator->cbs->link_account_response_cb(creator, LinphoneAccountCreatorStatusMissingArguments, "Missing required parameters");
945
		}
946
		return LinphoneAccountCreatorStatusMissingArguments;
947
	}
948
	request = linphone_xml_rpc_request_new_with_args(LinphoneXmlRpcArgString, "link_phone_number_with_account",
949 950
		LinphoneXmlRpcArgString, creator->phone_number,
		LinphoneXmlRpcArgString, creator->username,
951
		LinphoneXmlRpcArgString, linphone_proxy_config_get_domain(creator->proxy_cfg),
952
		LinphoneXmlRpcArgString, creator->language,
953 954
		LinphoneXmlRpcArgNone);
	linphone_xml_rpc_request_set_user_data(request, creator);
955
	linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _link_phone_number_with_account_cb_custom);
956 957
	linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request);
	linphone_xml_rpc_request_unref(request);
958
	return LinphoneAccountCreatorStatusRequestOk;
959
}
960

961
static void _get_phone_number_for_account_cb_custom(LinphoneXmlRpcRequest *request) {
962
	LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request);
963 964
	if (creator->cbs->is_account_linked_response_cb != NULL) {
		LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed;
965 966 967 968
		const char* resp = linphone_xml_rpc_request_get_string_response(request);
		if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
			status = (strcmp(resp, "ERROR_USERNAME_PARAMETER_NOT_FOUND") == 0
				|| strcmp(resp, "ERROR_ACCOUNT_DOESNT_EXIST") == 0
969
				|| strcmp(resp, "ERROR_ALIAS_DOESNT_EXIST") == 0) ? LinphoneAccountCreatorStatusAccountNotLinked : LinphoneAccountCreatorStatusAccountLinked;
970
		}
971
		creator->cbs->is_account_linked_response_cb(creator, status, resp);
972 973 974
	}
}

975
LinphoneAccountCreatorStatus linphone_account_creator_is_account_linked_linphone(LinphoneAccountCreator *creator) {
976 977
	LinphoneXmlRpcRequest *request;
	if (!creator->username || !linphone_proxy_config_get_domain(creator->proxy_cfg)) {
978
		return LinphoneAccountCreatorStatusMissingArguments;
979 980
	}
	request = linphone_xml_rpc_request_new_with_args(LinphoneXmlRpcArgString, "get_phone_number_for_account",
981
		LinphoneXmlRpcArgString, creator->username,
982
		LinphoneXmlRpcArgString, linphone_proxy_config_get_domain(creator->proxy_cfg),
983
		LinphoneXmlRpcArgNone);
984 985 986 987 988
	linphone_xml_rpc_request_set_user_data(request, creator);
	linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _get_phone_number_for_account_cb_custom);
	linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request);
	linphone_xml_rpc_request_unref(request);
	return LinphoneAccountCreatorStatusRequestOk;
989
}
990
/****************** END OF LINK PHONE NUMBER WITH ACCOUNT SECTION *************/
991

992
/****************** START OF ACTIVE PHONE NUMBER LINK **************************/
993
static void _activate_phone_number_link_cb_custom(LinphoneXmlRpcRequest *request) {
994
	LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request);
995 996
	if (creator->cbs->activate_alias_response_cb != NULL) {
		LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed;
997
		const char* resp = linphone_xml_rpc_request_get_string_response(request);
998
		if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
999
			status = (strstr(resp, "ERROR_") == resp) ? LinphoneAccountCreatorStatusAccountNotActivated : LinphoneAccountCreatorStatusAccountActivated;
1000
		}
1001
		creator->cbs->activate_alias_response_cb(creator, status, resp);
1002
	}
1003
}
1004

1005
LinphoneAccountCreatorStatus linphone_account_creator_activate_phone_number_link_linphone(LinphoneAccountCreator *creator) {
1006
	LinphoneXmlRpcRequest *request;
1007
	if (!creator->phone_number || !creator->username || !creator->activation_code || (!creator->password && !creator->ha1) || !linphone_proxy_config_get_domain(creator->proxy_cfg)) {
1008 1009
		if (creator->cbs->activate_alias_response_cb != NULL) {
			creator->cbs->activate_alias_response_cb(creator, LinphoneAccountCreatorStatusMissingArguments, "Missing required parameters");
1010
		}
1011
		return LinphoneAccountCreatorStatusMissingArguments;
1012
	}
1013
	request = linphone_xml_rpc_request_new_with_args(LinphoneXmlRpcArgString, "activate_phone_number_link",
1014 1015 1016
		LinphoneXmlRpcArgString, creator->phone_number,
		LinphoneXmlRpcArgString, creator->username,
		LinphoneXmlRpcArgString, creator->activation_code,
1017 1018
		LinphoneXmlRpcArgString, creator->ha1 ? creator->ha1 : ha1_for_passwd(creator->username, linphone_proxy_config_get_domain(creator->proxy_cfg), creator->password),
		LinphoneXmlRpcArgString, linphone_proxy_config_get_domain(creator->proxy_cfg),
1019 1020
		LinphoneXmlRpcArgNone);
	linphone_xml_rpc_request_set_user_data(request, creator);
1021
	linphone_xml_rpc_request_cbs_set_response(linphone_xml_rpc_request_get_callbacks(request), _activate_phone_number_link_cb_custom);
1022 1023
	linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request);
	linphone_xml_rpc_request_unref(request);
1024
	return LinphoneAccountCreatorStatusRequestOk;
1025
}
1026
/****************** END OF ACTIVE PHONE NUMBER LINK **************************/
1027 1028

/****************** START OF ACTIVE PHONE NUMBER LINK **************************/
1029
static void _recover_phone_account_cb_custom(LinphoneXmlRpcRequest *request) {
1030
	LinphoneAccountCreator *creator = (LinphoneAccountCreator *)linphone_xml_rpc_request_get_user_data(request);
1031 1032
	if (creator->cbs->recover_account_response_cb != NULL) {
		LinphoneAccountCreatorStatus status = LinphoneAccountCreatorStatusRequestFailed;
1033
		const char* resp = linphone_xml_rpc_request_get_string_response(request);
1034
		if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
1035
			if (strstr(resp, "ERROR_") == resp) {
1036 1037 1038
				status = (strstr(resp, "ERROR_CANNOT_SEND_SMS") == resp) ? LinphoneAccountCreatorStatusServerError
					: (strstr(resp, "ERROR_ACCOUNT_DOESNT_EXIST") == resp) ? LinphoneAccountCreatorStatusAccountNotExist
					: LinphoneAccountCreatorStatusRequestFailed;
1039
			} else {
1040
				status = LinphoneAccountCreatorStatusRequestOk;
1041 1042
				set_string(&creator->username, resp, FALSE);
			}
1043
		}