friend.c 14.7 KB
Newer Older
aymeric's avatar
aymeric committed
1 2 3 4
/***************************************************************************
 *            friend.c
 *
 *  Sat May 15 15:25:16 2004
5
 *  Copyright  2004-2009  Simon Morlat
aymeric's avatar
aymeric committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
 *  Email
 ****************************************************************************/

/*
 *  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.
 */

#include "linphonecore.h"
#include "private.h"
#include "lpconfig.h"

const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
	const char *str=NULL;
	switch(ss){
		case LINPHONE_STATUS_ONLINE:
		str=_("Online");
		break;
		case LINPHONE_STATUS_BUSY:
		str=_("Busy");
		break;
		case LINPHONE_STATUS_BERIGHTBACK:
		str=_("Be right back");
		break;
		case LINPHONE_STATUS_AWAY:
		str=_("Away");
		break;
		case LINPHONE_STATUS_ONTHEPHONE:
		str=_("On the phone");
		break;
		case LINPHONE_STATUS_OUTTOLUNCH:
		str=_("Out to lunch");
		break;
		case LINPHONE_STATUS_NOT_DISTURB:
		str=_("Do not disturb");
		break;
		case LINPHONE_STATUS_MOVED:
		str=_("Moved");
		break;
		case LINPHONE_STATUS_ALT_SERVICE:
		str=_("Using another messaging service");
		break;
		case LINPHONE_STATUS_OFFLINE:
		str=_("Offline");
		break;
		case LINPHONE_STATUS_PENDING:
		str=_("Pending");
		break;
		default:
		str=_("Unknown-bug");
	}
	return str;
}

static int friend_data_compare(const void * a, const void * b, void * data){
72 73
	LinphoneAddress *fa=((LinphoneFriend*)a)->uri;
	LinphoneAddress *fb=((LinphoneFriend*)b)->uri;
74
	const char *ua,*ub;
75 76
	ua=linphone_address_get_username(fa);
	ub=linphone_address_get_username(fb);
aymeric's avatar
aymeric committed
77 78 79 80 81 82
	if (ua!=NULL && ub!=NULL) {
		//printf("Comparing usernames %s,%s\n",ua,ub);
		return strcasecmp(ua,ub);
	}
	else {
		/* compare hosts*/
83 84
		ua=linphone_address_get_domain(fa);
		ub=linphone_address_get_domain(fb);
aymeric's avatar
aymeric committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98
		if (ua!=NULL && ub!=NULL){
			int ret=strcasecmp(ua,ub);
			//printf("Comparing hostnames %s,%s,res=%i\n",ua,ub,ret);
			return ret;
		}
		else return -1;
	}
}

static int friend_compare(const void * a, const void * b){
	return friend_data_compare(a,b,NULL);
}


99
MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *friend, LinphoneFriend **lf){
aymeric's avatar
aymeric committed
100 101 102
	MSList *res=NULL;
	LinphoneFriend dummy;
	if (lf!=NULL) *lf=NULL;
103
	dummy.uri=(LinphoneAddress*)friend;
aymeric's avatar
aymeric committed
104 105 106 107 108
	res=ms_list_find_custom(fl,friend_compare,&dummy);
	if (lf!=NULL && res!=NULL) *lf=(LinphoneFriend*)res->data;
	return res;
}

109
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){
aymeric's avatar
aymeric committed
110 111 112
	MSList *elem;
	for (elem=l;elem!=NULL;elem=elem->next){
		LinphoneFriend *lf=(LinphoneFriend*)elem->data;
113
		if (lf->insub==op) return lf;
aymeric's avatar
aymeric committed
114 115 116 117
	}
	return NULL;
}

118
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){
aymeric's avatar
aymeric committed
119 120 121
	MSList *elem;
	for (elem=l;elem!=NULL;elem=elem->next){
		LinphoneFriend *lf=(LinphoneFriend*)elem->data;
122
		if (lf->outsub==op) return lf;
aymeric's avatar
aymeric committed
123 124 125 126 127 128 129 130
	}
	return NULL;
}

void __linphone_friend_do_subscribe(LinphoneFriend *fr){
	char *friend=NULL;
	const char *route=NULL;
	const char *from=NULL;
131 132
	LinphoneProxyConfig *cfg;
	
133
	friend=linphone_address_as_string(fr->uri);
134 135 136 137
	cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr));
	if (cfg!=NULL){
		route=linphone_proxy_config_get_route(cfg);
		from=linphone_proxy_config_get_identity(cfg);
aymeric's avatar
aymeric committed
138
	}else from=linphone_core_get_primary_contact(fr->lc);
139
	if (fr->outsub==NULL){
aymeric's avatar
aymeric committed
140
		/* people for which we don't have yet an answer should appear as offline */
141
		fr->status=LINPHONE_STATUS_OFFLINE;
142
		/*
143
		if (fr->lc->vtable.notify_recv)
144
			fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
145
		 */
146 147 148 149 150 151 152
	}else{
		sal_op_release(fr->outsub);
		fr->outsub=NULL;
	}
	fr->outsub=sal_op_new(fr->lc->sal);
	sal_op_set_route(fr->outsub,route);
	sal_subscribe_presence(fr->outsub,from,friend);
153
	fr->subscribe_active=TRUE;
154
	ms_free(friend);
aymeric's avatar
aymeric committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
}

LinphoneFriend * linphone_friend_new(){
	LinphoneFriend *obj=ms_new0(LinphoneFriend,1);
	obj->pol=LinphoneSPAccept;
	obj->status=LINPHONE_STATUS_OFFLINE;
	obj->subscribe=TRUE;
	return obj;	
}

LinphoneFriend *linphone_friend_new_with_addr(const char *addr){
	LinphoneFriend *fr=linphone_friend_new();
	if (linphone_friend_set_sip_addr(fr,addr)<0){
		linphone_friend_destroy(fr);
		return NULL;
	}
	return fr;
}

174 175 176 177
bool_t linphone_friend_in_list(const LinphoneFriend *lf){
	return lf->lc!=NULL;
}

smorlat's avatar
smorlat committed
178
void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result){
179
	LinphoneAddress *fr=NULL;
180
	*result=NULL;
181
	fr=linphone_address_new(uri);
182
	if (fr==NULL){
smorlat's avatar
smorlat committed
183 184
		char *tmp=NULL;
		if (strchr(uri,'@')!=NULL){
185
			LinphoneAddress *u;
smorlat's avatar
smorlat committed
186 187
			/*try adding sip:*/
			tmp=ms_strdup_printf("sip:%s",uri);
188
			u=linphone_address_new(tmp);
189 190 191
			if (u!=NULL){
				*result=tmp;
			}
smorlat's avatar
smorlat committed
192 193
		}else if (lc->default_proxy!=NULL){
			/*try adding domain part from default current proxy*/
194
			LinphoneAddress * id=linphone_address_new(linphone_core_get_identity(lc));
195
			if (id!=NULL){
196 197 198
				linphone_address_set_username(id,uri);
				*result=linphone_address_as_string(id);
				linphone_address_destroy(id);
smorlat's avatar
smorlat committed
199 200
			}
		}
201
		if (*result){
smorlat's avatar
smorlat committed
202
			/*looks good */
203 204 205 206
			ms_message("%s interpreted as %s",uri,*result);
		}else{
			ms_warning("Fail to interpret friend uri %s",uri);
		}
207 208
	}else *result=linphone_address_as_string(fr);
	linphone_address_destroy(fr);
smorlat's avatar
smorlat committed
209
}
aymeric's avatar
aymeric committed
210 211

int linphone_friend_set_sip_addr(LinphoneFriend *lf, const char *addr){
212
	LinphoneAddress *fr=linphone_address_new(addr);
213
	if (fr==NULL) {
aymeric's avatar
aymeric committed
214 215 216
		ms_warning("Invalid friend sip uri: %s",addr);
		return -1;
	}
217
	linphone_address_clean(fr);
218
	if (lf->uri!=NULL) linphone_address_destroy(lf->uri);	
219
	lf->uri=fr;
aymeric's avatar
aymeric committed
220 221 222 223
	return 0;
}

int linphone_friend_set_name(LinphoneFriend *lf, const char *name){
224
	LinphoneAddress *fr=lf->uri;
aymeric's avatar
aymeric committed
225 226 227 228
	if (fr==NULL){
		ms_error("linphone_friend_set_sip_addr() must be called before linphone_friend_set_name().");
		return -1;
	}
229
	linphone_address_set_display_name(fr,name);
aymeric's avatar
aymeric committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243
	return 0;
}

int linphone_friend_send_subscribe(LinphoneFriend *fr, bool_t val){
	fr->subscribe=val;
	return 0;
}

int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol)
{
	fr->pol=pol;
	return 0;
}

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){
	switch(os){
		case LINPHONE_STATUS_OFFLINE:
			return SalPresenceOffline;
		break;
		case LINPHONE_STATUS_ONLINE:
			return SalPresenceOnline;
		break;
		case LINPHONE_STATUS_BUSY:
			return SalPresenceBusy;
		break;
		case LINPHONE_STATUS_BERIGHTBACK:
			return SalPresenceBerightback;
		break;
		case LINPHONE_STATUS_AWAY:
			return SalPresenceAway;
		break;
		case LINPHONE_STATUS_ONTHEPHONE:
			return SalPresenceOnthephone;
		break;
		case LINPHONE_STATUS_OUTTOLUNCH:
			return SalPresenceOuttolunch;
		break;
		case LINPHONE_STATUS_NOT_DISTURB:
			return SalPresenceDonotdisturb;
		break;
		case LINPHONE_STATUS_MOVED:
			return SalPresenceMoved;
		break;
		case LINPHONE_STATUS_ALT_SERVICE:
			return SalPresenceAltService;
		break;
		case LINPHONE_STATUS_PENDING:
			return SalPresenceOffline;
		break;
		default:
			return SalPresenceOffline;
		break;
	}
	return SalPresenceOffline;
aymeric's avatar
aymeric committed
284 285
}

286
void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){
aymeric's avatar
aymeric committed
287
	//printf("Wish to notify %p, lf->nid=%i\n",lf,lf->nid);
288 289
	if (lf->insub!=NULL){
		sal_notify_presence(lf->insub,linphone_online_status_to_sal(os),NULL);
aymeric's avatar
aymeric committed
290 291 292 293
	}
}

static void linphone_friend_unsubscribe(LinphoneFriend *lf){
294 295 296 297
	if (lf->outsub!=NULL) {
		sal_unsubscribe(lf->outsub);
		sal_op_release(lf->outsub);
		lf->outsub=NULL;
298
		lf->subscribe_active=FALSE;
aymeric's avatar
aymeric committed
299 300 301
	}
}

302
void linphone_friend_close_subscriptions(LinphoneFriend *lf){
aymeric's avatar
aymeric committed
303
	linphone_friend_unsubscribe(lf);
304 305 306
	if (lf->insub){
		sal_notify_close(lf->insub);
		sal_op_release(lf->insub);
307
		lf->insub=NULL;
308
	}
309 310 311 312
}

void linphone_friend_destroy(LinphoneFriend *lf){
	
313
	if (lf->uri!=NULL) linphone_address_destroy(lf->uri);
314
	if (lf->info!=NULL) buddy_info_free(lf->info);
aymeric's avatar
aymeric committed
315 316 317
	ms_free(lf);
}

318
const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf){
319
	return lf->uri;
aymeric's avatar
aymeric committed
320 321 322 323 324 325 326 327 328 329 330 331 332 333
}

bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf){
	return lf->subscribe;
}

LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf){
	return lf->pol;
}

LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){
	return lf->status;
}

334 335 336
BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){
	return lf->info;
}
aymeric's avatar
aymeric committed
337 338

void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
339
	if (fr->uri==NULL) {
aymeric's avatar
aymeric committed
340 341 342 343 344
		ms_warning("No sip url defined.");
		return;
	}
	fr->lc=lc;
	
345 346
	linphone_core_write_friends_config(lc);

aymeric's avatar
aymeric committed
347 348 349
	if (fr->inc_subscribe_pending){
		switch(fr->pol){
			case LinphoneSPWait:
350
				linphone_friend_notify(fr,LINPHONE_STATUS_PENDING);
aymeric's avatar
aymeric committed
351 352 353 354
				break;
			case LinphoneSPAccept:
				if (fr->lc!=NULL)
				  {
355
					linphone_friend_notify(fr,fr->lc->presence_mode);
aymeric's avatar
aymeric committed
356 357 358
				  }
				break;
			case LinphoneSPDeny:
359
				linphone_friend_notify(fr,LINPHONE_STATUS_OFFLINE);
aymeric's avatar
aymeric committed
360 361 362 363
				break;
		}
		fr->inc_subscribe_pending=FALSE;
	}
364
	if (fr->subscribe && fr->subscribe_active==FALSE){
365
		ms_message("Sending a new SUBSCRIBE");
aymeric's avatar
aymeric committed
366 367 368
		__linphone_friend_do_subscribe(fr);
	}
	ms_message("linphone_friend_apply() done.");
369
	lc->bl_refresh=TRUE;
aymeric's avatar
aymeric committed
370 371 372 373 374 375 376 377 378 379 380 381 382 383
}

void linphone_friend_edit(LinphoneFriend *fr){
}

void linphone_friend_done(LinphoneFriend *fr){
	ms_return_if_fail(fr!=NULL);
	if (fr->lc==NULL) return;
	linphone_friend_apply(fr,fr->lc);
}

void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf)
{
	ms_return_if_fail(lf->lc==NULL);
384
	ms_return_if_fail(lf->uri!=NULL);
385 386 387 388 389 390 391 392
	if (ms_list_find(lc->friends,lf)!=NULL){
		char *tmp=NULL;
		const LinphoneAddress *addr=linphone_friend_get_address(lf);
		if (addr) tmp=linphone_address_as_string(addr);
		ms_warning("Friend %s already in list, ignored.", tmp ? tmp : "unknown");
		if (tmp) ms_free(tmp);
		return ;
	}
aymeric's avatar
aymeric committed
393
	lc->friends=ms_list_append(lc->friends,lf);
smorlat's avatar
smorlat committed
394
	linphone_friend_apply(lf,lc);
aymeric's avatar
aymeric committed
395 396 397 398 399 400 401 402
	return ;
}

void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){
	MSList *el=ms_list_find(lc->friends,(void *)fl);
	if (el!=NULL){
		lc->friends=ms_list_remove_link(lc->friends,el);
		linphone_friend_destroy((LinphoneFriend*)el->data);
403
		linphone_core_write_friends_config(lc);
aymeric's avatar
aymeric committed
404 405 406
	}
}

407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key){
	if (lf->refkey!=NULL){
		ms_free(lf->refkey);
		lf->refkey=NULL;
	}
	if (key)
		lf->refkey=ms_strdup(key);
	if (lf->lc)
		linphone_core_write_friends_config(lf->lc);
}

const char *linphone_friend_get_ref_key(const LinphoneFriend *lf){
	return lf->refkey;
}

422 423 424 425 426 427
static bool_t username_match(const char *u1, const char *u2){
	if (u1==NULL && u2==NULL) return TRUE;
	if (u1 && u2 && strcasecmp(u1,u2)==0) return TRUE;
	return FALSE;
}

428
LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *uri){
429
	LinphoneAddress *puri=linphone_address_new(uri);
430
	const MSList *elem;
431 432
	const char *username=linphone_address_get_username(puri);
	const char *domain=linphone_address_get_domain(puri);
433 434 435
	LinphoneFriend *lf=NULL;
		
	if (puri==NULL){
436 437 438
		return NULL;
	}
	for(elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){
439
		lf=(LinphoneFriend*)elem->data;
440 441
		const char *it_username=linphone_address_get_username(lf->uri);
		const char *it_host=linphone_address_get_domain(lf->uri);;
442 443
		if (strcasecmp(domain,it_host)==0 && username_match(username,it_username)){
			break;
444
		}
445
		lf=NULL;
446
	}
447
	linphone_address_destroy(puri);
448
	return lf;
449 450
}

451 452 453 454 455 456 457 458 459 460 461 462
LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key){
	const MSList *elem;
	if (key==NULL) return NULL;
	for(elem=linphone_core_get_friend_list(lc);elem!=NULL;elem=elem->next){
		LinphoneFriend *lf=(LinphoneFriend*)elem->data;
		if (lf->refkey!=NULL && strcmp(lf->refkey,key)==0){
			return lf;
		}
	}
	return NULL;
}

smorlat's avatar
smorlat committed
463
#define key_compare(s1,s2)	strcmp(s1,s2)
aymeric's avatar
aymeric committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512

LinphoneSubscribePolicy __policy_str_to_enum(const char* pol){
	if (key_compare("accept",pol)==0){
		return LinphoneSPAccept;
	}
	if (key_compare("deny",pol)==0){
		return LinphoneSPDeny;
	}
	if (key_compare("wait",pol)==0){
		return LinphoneSPWait;
	}
	ms_warning("Unrecognized subscribe policy: %s",pol);
	return LinphoneSPWait;
}

LinphoneProxyConfig *__index_to_proxy(LinphoneCore *lc, int index){
	if (index>=0) return (LinphoneProxyConfig*)ms_list_nth_data(lc->sip_conf.proxies,index);
	else return NULL;
}

LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int index){
	const char *tmp;
	char item[50];
	int a;
	LinphoneFriend *lf;
	LpConfig *config=lc->config;
	
	sprintf(item,"friend_%i",index);
	
	if (!lp_config_has_section(config,item)){
		return NULL;
	}
	
	tmp=lp_config_get_string(config,item,"url",NULL);
	if (tmp==NULL) {
		return NULL;
	}
	lf=linphone_friend_new_with_addr(tmp);
	if (lf==NULL) {
		return NULL;
	}
	tmp=lp_config_get_string(config,item,"pol",NULL);
	if (tmp==NULL) linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPWait);
	else{
		linphone_friend_set_inc_subscribe_policy(lf,__policy_str_to_enum(tmp));
	}
	a=lp_config_get_int(config,item,"subscribe",0);
	linphone_friend_send_subscribe(lf,a);
		
513
	linphone_friend_set_ref_key(lf,lp_config_get_string(config,item,"refkey",NULL));
aymeric's avatar
aymeric committed
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
	return lf;
}

const char *__policy_enum_to_str(LinphoneSubscribePolicy pol){
	switch(pol){
		case LinphoneSPAccept:
			return "accept";
			break;
		case LinphoneSPDeny:
			return "deny";
			break;
		case LinphoneSPWait:
			return "wait";
			break;
	}
	ms_warning("Invalid policy enum value.");
	return "wait";
}

void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf, int index){
	char key[50];
	char *tmp;
536
	const char *refkey;
aymeric's avatar
aymeric committed
537 538 539 540 541 542 543
	
	sprintf(key,"friend_%i",index);
	
	if (lf==NULL){
		lp_config_clean_section(config,key);
		return;
	}
544
	if (lf->uri!=NULL){
545
		tmp=linphone_address_as_string(lf->uri);
aymeric's avatar
aymeric committed
546 547 548 549
		if (tmp==NULL) {
			return;
		}
		lp_config_set_string(config,key,"url",tmp);
Simon Morlat's avatar
Simon Morlat committed
550
		ms_free(tmp);
aymeric's avatar
aymeric committed
551 552 553
	}
	lp_config_set_string(config,key,"pol",__policy_enum_to_str(lf->pol));
	lp_config_set_int(config,key,"subscribe",lf->subscribe);
554 555 556 557 558

	refkey=linphone_friend_get_ref_key(lf);
	if (refkey){
		lp_config_set_string(config,key,"refkey",refkey);
	}
aymeric's avatar
aymeric committed
559
}
560 561 562 563 564 565 566 567 568 569 570 571

void linphone_core_write_friends_config(LinphoneCore* lc)
{
	MSList *elem;
	int i;
	if (!lc->ready) return; /*dont write config when reading it !*/
	for (elem=lc->friends,i=0; elem!=NULL; elem=ms_list_next(elem),i++){
		linphone_friend_write_to_config_file(lc->config,(LinphoneFriend*)elem->data,i);
	}
	linphone_friend_write_to_config_file(lc->config,NULL,i);	/* set the end */
}