1 /***************************************************************************
2 * friend.c
3 *
4 * Sat May 15 15:25:16 2004
5 * Copyright 2004-2009 Simon Morlat
6 * Email
7 ****************************************************************************/
8
9 /*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25 #include "linphone/core.h"
26 #include "private.h"
27 #include "linphone/lpconfig.h"
28
29 #ifdef SQLITE_STORAGE_ENABLED
30 #ifndef _WIN32
31 #if !defined(__ANDROID__) && !defined(__QNXNTO__)
32 # include <langinfo.h>
33 # include <iconv.h>
34 # include <string.h>
35 #endif
36 #else
37 #include <Windows.h>
38 #endif
39
40 #define MAX_PATH_SIZE 1024
41 #include "sqlite3.h"
42 #endif
43
linphone_online_status_to_string(LinphoneOnlineStatus ss)44 const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
45 const char *str=NULL;
46 switch(ss){
47 case LinphoneStatusOnline:
48 str=_("Online");
49 break;
50 case LinphoneStatusBusy:
51 str=_("Busy");
52 break;
53 case LinphoneStatusBeRightBack:
54 str=_("Be right back");
55 break;
56 case LinphoneStatusAway:
57 str=_("Away");
58 break;
59 case LinphoneStatusOnThePhone:
60 str=_("On the phone");
61 break;
62 case LinphoneStatusOutToLunch:
63 str=_("Out to lunch");
64 break;
65 case LinphoneStatusDoNotDisturb:
66 str=_("Do not disturb");
67 break;
68 case LinphoneStatusMoved:
69 str=_("Moved");
70 break;
71 case LinphoneStatusAltService:
72 str=_("Using another messaging service");
73 break;
74 case LinphoneStatusOffline:
75 str=_("Offline");
76 break;
77 case LinphoneStatusPending:
78 str=_("Pending");
79 break;
80 case LinphoneStatusVacation:
81 str=_("Vacation");
82 break;
83 default:
84 str=_("Unknown status");
85 }
86 return str;
87 }
88
friend_compare(const void * a,const void * b)89 static int friend_compare(const void * a, const void * b) {
90 LinphoneFriend *lfa = (LinphoneFriend *)a;
91 LinphoneFriend *lfb = (LinphoneFriend *)b;
92 const bctbx_list_t *addressesa = linphone_friend_get_addresses(lfa);
93 const bctbx_list_t *addressesb = linphone_friend_get_addresses(lfb);
94 bctbx_list_t *iteratora = (bctbx_list_t *)addressesa;
95 bctbx_list_t *iteratorb = (bctbx_list_t *)addressesb;
96 int ret = 1;
97
98 while (iteratora && (ret == 1)) {
99 LinphoneAddress *fa = (LinphoneAddress *)bctbx_list_get_data(iteratora);
100 while (iteratorb && (ret == 1)) {
101 LinphoneAddress *fb = (LinphoneAddress *)bctbx_list_get_data(iteratorb);
102 if (linphone_address_weak_equal(fa, fb)) ret = 0;
103 iteratorb = bctbx_list_next(iteratorb);
104 }
105 iteratora = bctbx_list_next(iteratora);
106 }
107
108 return ret;
109 }
110
find_presence_model_for_uri_or_tel(const LinphoneFriend * lf,const char * uri_or_tel)111 static LinphoneFriendPresence * find_presence_model_for_uri_or_tel(const LinphoneFriend *lf, const char *uri_or_tel) {
112 bctbx_list_t *iterator = NULL;
113 LinphoneAddress *uri_or_tel_addr = NULL;
114 LinphoneFriendPresence *result=NULL;
115 if (!lf->lc) {
116 ms_warning("Cannot find uri of tel [%s] from friend [%p] because not associated to any Linphone core object",uri_or_tel,lf);
117 return NULL;
118 }
119 if ((iterator = lf->presence_models) == NULL) {
120 /*no need to move forward, just reutn to avoid useless uri parsing*/
121 return NULL;
122 };
123
124 uri_or_tel_addr = linphone_core_interpret_url(lf->lc, uri_or_tel);
125
126 while (uri_or_tel_addr && iterator) {
127 LinphoneFriendPresence *lfp = (LinphoneFriendPresence *)bctbx_list_get_data(iterator);
128 LinphoneAddress *lfp_addr = linphone_core_interpret_url(lf->lc, lfp->uri_or_tel);
129 if (lfp_addr && linphone_address_weak_equal(uri_or_tel_addr, lfp_addr)) {
130 result = lfp;
131 }
132 if (lfp_addr) linphone_address_unref(lfp_addr);
133 if (result == NULL)
134 iterator = bctbx_list_next(iterator);
135 else
136 break;
137 }
138 if (uri_or_tel_addr) linphone_address_unref(uri_or_tel_addr);
139 return result;
140 }
141
add_presence_model_for_uri_or_tel(LinphoneFriend * lf,const char * uri_or_tel,LinphonePresenceModel * presence)142 static void add_presence_model_for_uri_or_tel(LinphoneFriend *lf, const char *uri_or_tel, LinphonePresenceModel *presence) {
143 LinphoneFriendPresence *lfp = ms_new0(LinphoneFriendPresence, 1);
144 lfp->uri_or_tel = ms_strdup(uri_or_tel);
145 lfp->presence = presence;
146 lf->presence_models = bctbx_list_append(lf->presence_models, lfp);
147 }
148
free_friend_presence(LinphoneFriendPresence * lfp)149 static void free_friend_presence(LinphoneFriendPresence *lfp) {
150 ms_free(lfp->uri_or_tel);
151 if (lfp->presence) linphone_presence_model_unref(lfp->presence);
152 ms_free(lfp);
153 }
154
free_phone_number_sip_uri(LinphoneFriendPhoneNumberSipUri * lfpnsu)155 static void free_phone_number_sip_uri(LinphoneFriendPhoneNumberSipUri *lfpnsu) {
156 ms_free(lfpnsu->number);
157 ms_free(lfpnsu->uri);
158 ms_free(lfpnsu);
159 }
160
161
162
linphone_find_friend_by_address(bctbx_list_t * fl,const LinphoneAddress * addr,LinphoneFriend ** lf)163 bctbx_list_t *linphone_find_friend_by_address(bctbx_list_t *fl, const LinphoneAddress *addr, LinphoneFriend **lf){
164 bctbx_list_t *res=NULL;
165 LinphoneFriend dummy;
166 if (lf!=NULL) *lf=NULL;
167 memset(&dummy, 0, sizeof(LinphoneFriend));
168 dummy.uri=(LinphoneAddress*)addr;
169 res=bctbx_list_find_custom(fl,friend_compare,&dummy);
170 if (lf!=NULL && res!=NULL) *lf=(LinphoneFriend*)bctbx_list_get_data(res);
171 return res;
172 }
173
__linphone_friend_do_subscribe(LinphoneFriend * fr)174 void __linphone_friend_do_subscribe(LinphoneFriend *fr){
175 LinphoneCore *lc=fr->lc;
176 const LinphoneAddress *addr = linphone_friend_get_address(fr);
177
178 if (addr != NULL) {
179 if (fr->outsub==NULL){
180 /* people for which we don't have yet an answer should appear as offline */
181 fr->presence_models = bctbx_list_free_with_data(fr->presence_models, (bctbx_list_free_func)free_friend_presence);
182 /*
183 if (fr->lc->vtable.notify_recv)
184 fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
185 */
186 }else{
187 sal_op_release(fr->outsub);
188 fr->outsub=NULL;
189 }
190 fr->outsub=sal_op_new(lc->sal);
191 linphone_configure_op(lc,fr->outsub,addr,NULL,TRUE);
192 sal_subscribe_presence(fr->outsub,NULL,NULL,lp_config_get_int(lc->config,"sip","subscribe_expires",600));
193 fr->subscribe_active=TRUE;
194 }
195 }
196
linphone_friend_new(void)197 LinphoneFriend * linphone_friend_new(void){
198 LinphoneFriend *obj = belle_sip_object_new(LinphoneFriend);
199 obj->pol = LinphoneSPAccept;
200 obj->subscribe = TRUE;
201 obj->vcard = NULL;
202 obj->storage_id = 0;
203 return obj;
204 }
205
206 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
207 #pragma GCC diagnostic push
208 #endif
209 #ifdef _MSC_VER
210 #pragma warning(disable : 4996)
211 #else
212 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
213 #endif
linphone_friend_new_with_address(const char * addr)214 LinphoneFriend *linphone_friend_new_with_address(const char *addr){
215 LinphoneAddress* linphone_address = linphone_address_new(addr);
216 LinphoneFriend *fr;
217
218 if (linphone_address == NULL) {
219 ms_error("Cannot create friend for address [%s]",addr?addr:"null");
220 return NULL;
221 }
222 fr=linphone_friend_new();
223 linphone_friend_set_address(fr,linphone_address);
224 linphone_address_unref(linphone_address);
225 return fr;
226 }
227 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
228 #pragma GCC diagnostic pop
229 #endif
230
linphone_friend_set_user_data(LinphoneFriend * lf,void * data)231 void linphone_friend_set_user_data(LinphoneFriend *lf, void *data){
232 lf->user_data=data;
233 }
234
linphone_friend_get_user_data(const LinphoneFriend * lf)235 void* linphone_friend_get_user_data(const LinphoneFriend *lf){
236 return lf->user_data;
237 }
238
linphone_friend_in_list(const LinphoneFriend * lf)239 bool_t linphone_friend_in_list(const LinphoneFriend *lf) {
240 return lf->friend_list != NULL;
241 }
242
linphone_core_interpret_friend_uri(LinphoneCore * lc,const char * uri,char ** result)243 void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result){
244 LinphoneAddress *fr=NULL;
245 *result=NULL;
246 fr=linphone_address_new(uri);
247 if (fr==NULL){
248 char *tmp=NULL;
249 if (strchr(uri,'@')!=NULL){
250 LinphoneAddress *u;
251 /*try adding sip:*/
252 tmp=ms_strdup_printf("sip:%s",uri);
253 u=linphone_address_new(tmp);
254 if (u!=NULL){
255 *result=tmp;
256 }
257 }else if (lc->default_proxy!=NULL){
258 /*try adding domain part from default current proxy*/
259 LinphoneAddress * id=linphone_address_new(linphone_core_get_identity(lc));
260 if ((id!=NULL) && (uri[0] != '\0')){
261 linphone_address_set_display_name(id,NULL);
262 linphone_address_set_username(id,uri);
263 *result=linphone_address_as_string(id);
264 linphone_address_unref(id);
265 }
266 }
267 if (*result){
268 /*looks good */
269 ms_message("%s interpreted as %s",uri,*result);
270 }else{
271 ms_warning("Fail to interpret friend uri %s",uri);
272 }
273 }else {
274 *result=linphone_address_as_string(fr);
275 linphone_address_unref(fr);
276 }
277 }
278
linphone_friend_get_address(const LinphoneFriend * lf)279 const LinphoneAddress * linphone_friend_get_address(const LinphoneFriend *lf) {
280 if (linphone_core_vcard_supported()) {
281 if (lf->vcard) {
282 const bctbx_list_t *sip_addresses = linphone_vcard_get_sip_addresses(lf->vcard);
283 if (sip_addresses) {
284 LinphoneAddress *addr = (LinphoneAddress *)bctbx_list_nth_data(sip_addresses, 0);
285 return addr;
286 }
287 }
288 return NULL;
289 }
290 if (lf->uri) return lf->uri;
291 return NULL;
292 }
293
linphone_friend_set_address(LinphoneFriend * lf,const LinphoneAddress * addr)294 LinphoneStatus linphone_friend_set_address(LinphoneFriend *lf, const LinphoneAddress *addr) {
295 LinphoneAddress *fr = linphone_address_clone(addr);
296 char *address;
297 const LinphoneAddress *mAddr = linphone_friend_get_address(lf);
298 if(mAddr && lf->friend_list) {
299 char *mainAddress = linphone_address_as_string_uri_only(mAddr);
300 bctbx_iterator_t *it = bctbx_map_cchar_find_key(lf->friend_list->friends_map_uri, mainAddress);
301 if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(lf->friend_list->friends_map_uri))){
302 linphone_friend_unref((LinphoneFriend*)bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it)));
303 bctbx_map_cchar_erase(lf->friend_list->friends_map_uri, it);
304 }
305 bctbx_iterator_cchar_delete(it);
306 }
307 linphone_address_clean(fr);
308 address = linphone_address_as_string_uri_only(fr);
309 if(lf->friend_list) {
310 bctbx_pair_t *pair = (bctbx_pair_t*) bctbx_pair_cchar_new(address, linphone_friend_ref(lf));
311 bctbx_map_cchar_insert_and_delete(lf->friend_list->friends_map_uri, pair);
312 }
313
314 if (linphone_core_vcard_supported()) {
315 if (!lf->vcard) {
316 const char *dpname = linphone_address_get_display_name(fr) ? linphone_address_get_display_name(fr) : linphone_address_get_username(fr);
317 linphone_friend_create_vcard(lf, dpname);
318 }
319 linphone_vcard_edit_main_sip_address(lf->vcard, address);
320 linphone_address_unref(fr);
321 } else {
322 if (lf->uri != NULL) linphone_address_unref(lf->uri);
323 lf->uri = fr;
324 }
325
326 ms_free(address);
327 return 0;
328 }
329
linphone_friend_add_address(LinphoneFriend * lf,const LinphoneAddress * addr)330 void linphone_friend_add_address(LinphoneFriend *lf, const LinphoneAddress *addr) {
331 LinphoneAddress *fr;
332 char *uri;
333 if (!lf || !addr) return;
334
335 fr = linphone_address_clone(addr);
336 linphone_address_clean(fr);
337 uri = linphone_address_as_string_uri_only(fr);
338 if(lf->friend_list) {
339 bctbx_pair_t *pair = (bctbx_pair_t*) bctbx_pair_cchar_new(uri, linphone_friend_ref(lf));
340 bctbx_map_cchar_insert_and_delete(lf->friend_list->friends_map_uri, pair);
341 }
342
343 if (linphone_core_vcard_supported()) {
344 if (lf->vcard) {
345 linphone_vcard_add_sip_address(lf->vcard, uri);
346 linphone_address_unref(fr);
347 }
348 } else {
349 if (lf->uri == NULL) lf->uri = fr;
350 else linphone_address_unref(fr);
351 }
352 ms_free(uri);
353 }
354
linphone_friend_get_addresses(const LinphoneFriend * lf)355 const bctbx_list_t* linphone_friend_get_addresses(const LinphoneFriend *lf) {
356 if (!lf) return NULL;
357
358 if (linphone_core_vcard_supported()) {
359 const bctbx_list_t * addresses = linphone_vcard_get_sip_addresses(lf->vcard);
360 return addresses;
361 } else {
362 bctbx_list_t *addresses = NULL;
363 return lf->uri ? bctbx_list_append(addresses, lf->uri) : NULL;
364 }
365 }
366
linphone_friend_remove_address(LinphoneFriend * lf,const LinphoneAddress * addr)367 void linphone_friend_remove_address(LinphoneFriend *lf, const LinphoneAddress *addr) {
368 char *address ;
369 if (!lf || !addr || !lf->vcard) return;
370
371 address = linphone_address_as_string_uri_only(addr);
372 if(lf->friend_list) {
373 bctbx_iterator_t *it = bctbx_map_cchar_find_key(lf->friend_list->friends_map_uri, address);
374 if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(lf->friend_list->friends_map_uri))){
375 linphone_friend_unref((LinphoneFriend*)bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it)));
376 bctbx_map_cchar_erase(lf->friend_list->friends_map_uri, it);
377 }
378 bctbx_iterator_cchar_delete(it);
379 }
380
381 if (linphone_core_vcard_supported()) {
382 linphone_vcard_remove_sip_address(lf->vcard, address);
383 }
384 ms_free(address);
385 }
386
linphone_friend_add_phone_number(LinphoneFriend * lf,const char * phone)387 void linphone_friend_add_phone_number(LinphoneFriend *lf, const char *phone) {
388 if (!lf || !phone) return;
389
390 if(lf->friend_list) {
391 const char *uri = linphone_friend_phone_number_to_sip_uri(lf, phone);
392 if(uri) {
393 bctbx_pair_t *pair = (bctbx_pair_t*) bctbx_pair_cchar_new(uri, linphone_friend_ref(lf));
394 bctbx_map_cchar_insert_and_delete(lf->friend_list->friends_map_uri, pair);
395 }
396 }
397
398 if (linphone_core_vcard_supported()) {
399 if (!lf->vcard) {
400 linphone_friend_create_vcard(lf, phone);
401 }
402 linphone_vcard_add_phone_number(lf->vcard, phone);
403 }
404 }
405
linphone_friend_get_phone_numbers(LinphoneFriend * lf)406 bctbx_list_t* linphone_friend_get_phone_numbers(LinphoneFriend *lf) {
407 if (!lf || !lf->vcard) return NULL;
408
409 if (linphone_core_vcard_supported()) {
410 return linphone_vcard_get_phone_numbers(lf->vcard);
411 }
412 return NULL;
413 }
414
linphone_friend_remove_phone_number(LinphoneFriend * lf,const char * phone)415 void linphone_friend_remove_phone_number(LinphoneFriend *lf, const char *phone) {
416 if (!lf || !phone || !lf->vcard) return;
417
418 if(lf->friend_list) {
419 const char *uri = linphone_friend_phone_number_to_sip_uri(lf, phone);
420 if(uri) {
421 bctbx_iterator_t *it = bctbx_map_cchar_find_key(lf->friend_list->friends_map_uri, uri);
422 if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(lf->friend_list->friends_map_uri))){
423 linphone_friend_unref((LinphoneFriend*)bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it)));
424 bctbx_map_cchar_erase(lf->friend_list->friends_map_uri, it);
425 }
426 bctbx_iterator_cchar_delete(it);
427 }
428 }
429
430 if (linphone_core_vcard_supported()) {
431 linphone_vcard_remove_phone_number(lf->vcard, phone);
432 }
433 }
434
linphone_friend_set_name(LinphoneFriend * lf,const char * name)435 LinphoneStatus linphone_friend_set_name(LinphoneFriend *lf, const char *name){
436 if (linphone_core_vcard_supported()) {
437 if (!lf->vcard) linphone_friend_create_vcard(lf, name);
438 linphone_vcard_set_full_name(lf->vcard, name);
439 } else {
440 if (!lf->uri) {
441 ms_warning("linphone_friend_set_address() must be called before linphone_friend_set_name() to be able to set display name.");
442 return -1;
443 }
444 linphone_address_set_display_name(lf->uri, name);
445 }
446 return 0;
447 }
448
linphone_friend_enable_subscribes(LinphoneFriend * fr,bool_t val)449 LinphoneStatus linphone_friend_enable_subscribes(LinphoneFriend *fr, bool_t val){
450 fr->subscribe=val;
451 return 0;
452 }
453
linphone_friend_set_inc_subscribe_policy(LinphoneFriend * fr,LinphoneSubscribePolicy pol)454 LinphoneStatus linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol) {
455 fr->pol=pol;
456 return 0;
457 }
458
linphone_friend_notify(LinphoneFriend * lf,LinphonePresenceModel * presence)459 void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence){
460 bctbx_list_t *elem;
461 if (lf->insubs){
462 const LinphoneAddress *addr = linphone_friend_get_address(lf);
463 if (addr) {
464 char *addr_str = linphone_address_as_string(addr);
465 ms_message("Want to notify %s", addr_str);
466 ms_free(addr_str);
467 }
468 }
469 for(elem=lf->insubs; elem!=NULL; elem=bctbx_list_next(elem)){
470 SalOp *op = (SalOp*)bctbx_list_get_data(elem);
471 sal_notify_presence(op,(SalPresenceModel *)presence);
472 }
473 }
474
linphone_friend_add_incoming_subscription(LinphoneFriend * lf,SalOp * op)475 void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op){
476 /*ownership of the op is transfered from sal to the LinphoneFriend*/
477 lf->insubs = bctbx_list_append(lf->insubs, op);
478 }
479
linphone_friend_remove_incoming_subscription(LinphoneFriend * lf,SalOp * op)480 void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op){
481 if (bctbx_list_find(lf->insubs, op)){
482 sal_op_release(op);
483 lf->insubs = bctbx_list_remove(lf->insubs, op);
484 }
485 }
486
linphone_friend_unsubscribe(LinphoneFriend * lf)487 static void linphone_friend_unsubscribe(LinphoneFriend *lf){
488 if (lf->outsub!=NULL) {
489 sal_unsubscribe(lf->outsub);
490 }
491 /* for friend list there is no necessary outsub*/
492 lf->subscribe_active=FALSE;
493 }
494
linphone_friend_invalidate_subscription(LinphoneFriend * lf)495 void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
496 bctbx_list_t *iterator;
497 LinphoneCore *lc=lf->lc;
498
499 if (lf->outsub!=NULL) {
500 sal_op_release(lf->outsub);
501 lf->outsub=NULL;
502 }
503
504 // To resend a subscribe on the next network_reachable(TRUE)
505 lf->subscribe_active=FALSE;
506
507 /* Notify application that we no longer know the presence activity */
508 iterator = lf->presence_models;
509 while (iterator) {
510 LinphoneFriendPresence *lfp = (LinphoneFriendPresence *)bctbx_list_get_data(iterator);
511 linphone_presence_model_unref(lfp->presence);
512 lfp->presence = linphone_presence_model_new();
513 linphone_presence_model_set_basic_status(lfp->presence, LinphonePresenceBasicStatusClosed);
514 linphone_core_notify_notify_presence_received_for_uri_or_tel(lc, lf, lfp->uri_or_tel, lfp->presence);
515 iterator = bctbx_list_next(iterator);
516 }
517 if (bctbx_list_size(lf->presence_models) > 0)
518 linphone_core_notify_notify_presence_received(lc, lf);
519
520 lf->initial_subscribes_sent=FALSE;
521 }
522
linphone_friend_close_incoming_subscriptions(LinphoneFriend * lf)523 static void linphone_friend_close_incoming_subscriptions(LinphoneFriend *lf) {
524 bctbx_list_for_each(lf->insubs, (MSIterateFunc) sal_notify_presence_close);
525 lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc)sal_op_release);
526 }
527
linphone_friend_close_subscriptions(LinphoneFriend * lf)528 void linphone_friend_close_subscriptions(LinphoneFriend *lf){
529 linphone_friend_unsubscribe(lf);
530 linphone_friend_close_incoming_subscriptions(lf);
531 }
532
_linphone_friend_release_ops(LinphoneFriend * lf)533 static void _linphone_friend_release_ops(LinphoneFriend *lf){
534 lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc) sal_op_release);
535 if (lf->outsub){
536 sal_op_release(lf->outsub);
537 lf->outsub=NULL;
538 }
539 }
540
_linphone_friend_destroy(LinphoneFriend * lf)541 static void _linphone_friend_destroy(LinphoneFriend *lf){
542 _linphone_friend_release_ops(lf);
543 if (lf->presence_models) bctbx_list_free_with_data(lf->presence_models, (bctbx_list_free_func)free_friend_presence);
544 if (lf->phone_number_sip_uri_map) bctbx_list_free_with_data(lf->phone_number_sip_uri_map, (bctbx_list_free_func)free_phone_number_sip_uri);
545 if (lf->uri!=NULL) linphone_address_unref(lf->uri);
546 if (lf->info!=NULL) buddy_info_free(lf->info);
547 if (lf->vcard != NULL) linphone_vcard_unref(lf->vcard);
548 if (lf->refkey != NULL) ms_free(lf->refkey);
549 }
550
_linphone_friend_marshall(belle_sip_object_t * obj,char * buff,size_t buff_size,size_t * offset)551 static belle_sip_error_code _linphone_friend_marshall(belle_sip_object_t *obj, char* buff, size_t buff_size, size_t *offset) {
552 LinphoneFriend *lf = (LinphoneFriend*)obj;
553 belle_sip_error_code err = BELLE_SIP_OK;
554 if (lf->uri){
555 char *tmp = linphone_address_as_string(lf->uri);
556 err = belle_sip_snprintf(buff, buff_size, offset, "%s", tmp);
557 ms_free(tmp);
558 }
559 return err;
560 }
561
linphone_friend_get_name(const LinphoneFriend * lf)562 const char * linphone_friend_get_name(const LinphoneFriend *lf) {
563 if (!lf) return NULL;
564
565 if (linphone_core_vcard_supported()) {
566 if (lf->vcard) return linphone_vcard_get_full_name(lf->vcard);
567 } else if (lf->uri) {
568 return linphone_address_get_display_name(lf->uri);
569 }
570 return NULL;
571 }
572
linphone_friend_get_send_subscribe(const LinphoneFriend * lf)573 bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf){
574 return lf->subscribe;
575 }
576
linphone_friend_get_inc_subscribe_policy(const LinphoneFriend * lf)577 LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf){
578 return lf->pol;
579 }
580
linphone_friend_get_status(const LinphoneFriend * lf)581 LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){
582 const LinphonePresenceModel *presence = linphone_friend_get_presence_model(lf);
583 LinphoneOnlineStatus online_status = LinphoneStatusOffline;
584 LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusClosed;
585 LinphonePresenceActivity *activity = NULL;
586 const char *description = NULL;
587 unsigned int nb_activities = 0;
588
589 if (presence != NULL) {
590 basic_status = linphone_presence_model_get_basic_status(presence);
591 nb_activities = linphone_presence_model_get_nb_activities(presence);
592 online_status = (basic_status == LinphonePresenceBasicStatusOpen) ? LinphoneStatusOnline : LinphoneStatusOffline;
593 if (nb_activities > 1) {
594 char *tmp = NULL;
595 const LinphoneAddress *addr = linphone_friend_get_address(lf);
596 if (addr) tmp = linphone_address_as_string(addr);
597 ms_warning("Friend %s has several activities, get status from the first one", tmp ? tmp : "unknown");
598 if (tmp) {
599 ms_free(tmp);
600 }
601 nb_activities = 1;
602 }
603 if (nb_activities == 1) {
604 activity = linphone_presence_model_get_activity(presence);
605 description = linphone_presence_activity_get_description(activity);
606 switch (linphone_presence_activity_get_type(activity)) {
607 case LinphonePresenceActivityBreakfast:
608 case LinphonePresenceActivityDinner:
609 case LinphonePresenceActivityLunch:
610 case LinphonePresenceActivityMeal:
611 online_status = LinphoneStatusOutToLunch;
612 break;
613 case LinphonePresenceActivityAppointment:
614 case LinphonePresenceActivityMeeting:
615 case LinphonePresenceActivityPerformance:
616 case LinphonePresenceActivityPresentation:
617 case LinphonePresenceActivitySpectator:
618 case LinphonePresenceActivityWorking:
619 case LinphonePresenceActivityWorship:
620 online_status = LinphoneStatusDoNotDisturb;
621 break;
622 case LinphonePresenceActivityAway:
623 case LinphonePresenceActivitySleeping:
624 online_status = LinphoneStatusAway;
625 break;
626 case LinphonePresenceActivityHoliday:
627 case LinphonePresenceActivityTravel:
628 case LinphonePresenceActivityVacation:
629 online_status = LinphoneStatusVacation;
630 break;
631 case LinphonePresenceActivityBusy:
632 if (description && strcmp(description, "Do not disturb") == 0) { // See linphonecore.c linphone_core_set_presence_info() method
633 online_status = LinphoneStatusDoNotDisturb;
634 } else {
635 online_status = LinphoneStatusBusy;
636 }
637 break;
638 case LinphonePresenceActivityLookingForWork:
639 case LinphonePresenceActivityPlaying:
640 case LinphonePresenceActivityShopping:
641 case LinphonePresenceActivityTV:
642 online_status = LinphoneStatusBusy;
643 break;
644 case LinphonePresenceActivityInTransit:
645 case LinphonePresenceActivitySteering:
646 online_status = LinphoneStatusBeRightBack;
647 break;
648 case LinphonePresenceActivityOnThePhone:
649 online_status = LinphoneStatusOnThePhone;
650 break;
651 case LinphonePresenceActivityOther:
652 case LinphonePresenceActivityPermanentAbsence:
653 online_status = LinphoneStatusMoved;
654 break;
655 case LinphonePresenceActivityUnknown:
656 /* Rely on the basic status information. */
657 break;
658 }
659 }
660 }
661
662 return online_status;
663 }
664
linphone_friend_get_presence_model(const LinphoneFriend * lf)665 const LinphonePresenceModel * linphone_friend_get_presence_model(const LinphoneFriend *lf) {
666 const LinphonePresenceModel *presence = NULL;
667 LinphoneFriend* const_lf = (LinphoneFriend*)lf;
668 const bctbx_list_t* addrs = linphone_friend_get_addresses(const_lf);
669 bctbx_list_t* phones = NULL;
670 bctbx_list_t *it;
671
672 for (it = (bctbx_list_t *)addrs; it!= NULL; it = it->next) {
673 LinphoneAddress *addr = (LinphoneAddress*)it->data;
674 char *uri = linphone_address_as_string_uri_only(addr);
675 presence = linphone_friend_get_presence_model_for_uri_or_tel(const_lf, uri);
676 ms_free(uri);
677 if (presence) break;
678 }
679 if (presence) return presence;
680
681 phones = linphone_friend_get_phone_numbers(const_lf);
682 for (it = phones; it!= NULL; it = it->next) {
683 presence = linphone_friend_get_presence_model_for_uri_or_tel(const_lf, it->data);
684 if (presence) break;
685 }
686 bctbx_list_free(phones);
687 return presence;
688 }
689
linphone_friend_get_consolidated_presence(const LinphoneFriend * lf)690 LinphoneConsolidatedPresence linphone_friend_get_consolidated_presence(const LinphoneFriend *lf) {
691 const LinphonePresenceModel *model = linphone_friend_get_presence_model(lf);
692 if (!model) return LinphoneConsolidatedPresenceOffline;
693 return linphone_presence_model_get_consolidated_presence(model);
694 }
695
linphone_friend_get_presence_model_for_uri_or_tel(const LinphoneFriend * lf,const char * uri_or_tel)696 const LinphonePresenceModel * linphone_friend_get_presence_model_for_uri_or_tel(const LinphoneFriend *lf, const char *uri_or_tel) {
697 LinphoneFriendPresence *lfp = find_presence_model_for_uri_or_tel(lf, uri_or_tel);
698 if (lfp) return lfp->presence;
699 return NULL;
700 }
701
linphone_friend_set_presence_model(LinphoneFriend * lf,LinphonePresenceModel * presence)702 void linphone_friend_set_presence_model(LinphoneFriend *lf, LinphonePresenceModel *presence) {
703 const LinphoneAddress *addr = linphone_friend_get_address(lf);
704 if (addr) {
705 char *uri = linphone_address_as_string_uri_only(addr);
706 linphone_friend_set_presence_model_for_uri_or_tel(lf, uri, presence);
707 ms_free(uri);
708 }
709 }
710
linphone_friend_set_presence_model_for_uri_or_tel(LinphoneFriend * lf,const char * uri_or_tel,LinphonePresenceModel * presence)711 void linphone_friend_set_presence_model_for_uri_or_tel(LinphoneFriend *lf, const char *uri_or_tel, LinphonePresenceModel *presence) {
712 LinphoneFriendPresence *lfp = find_presence_model_for_uri_or_tel(lf, uri_or_tel);
713 if (lfp) {
714 if (lfp->presence) linphone_presence_model_unref(lfp->presence);
715 lfp->presence = presence;
716 } else {
717 add_presence_model_for_uri_or_tel(lf, uri_or_tel, presence);
718 }
719 }
720
linphone_friend_is_presence_received(const LinphoneFriend * lf)721 bool_t linphone_friend_is_presence_received(const LinphoneFriend *lf) {
722 return lf->presence_received;
723 }
724
linphone_friend_get_info(const LinphoneFriend * lf)725 BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){
726 return lf->info;
727 }
728
729 /*
730 * updates the p2p subscriptions.
731 * If only_when_registered is TRUE, subscribe will be sent only if the friend's corresponding proxy config is in registered.
732 * Otherwise if the proxy config goes to unregistered state, the subscription refresh will be suspended.
733 * An optional proxy whose state has changed can be passed to optimize the processing.
734 **/
linphone_friend_update_subscribes(LinphoneFriend * fr,bool_t only_when_registered)735 void linphone_friend_update_subscribes(LinphoneFriend *fr, bool_t only_when_registered){
736 int can_subscribe=1;
737
738 if (only_when_registered && (fr->subscribe || fr->subscribe_active)){
739 const LinphoneAddress *addr = linphone_friend_get_address(fr);
740 if (addr != NULL) {
741 LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(fr->lc, addr);
742 if (cfg && cfg->state!=LinphoneRegistrationOk){
743 char *tmp=linphone_address_as_string(addr);
744 ms_message("Friend [%s] belongs to proxy config with identity [%s], but this one isn't registered. Subscription is suspended.",
745 tmp,linphone_proxy_config_get_identity(cfg));
746 ms_free(tmp);
747 can_subscribe=0;
748 }
749 }
750 }
751 if (can_subscribe && fr->subscribe && fr->subscribe_active==FALSE){
752 ms_message("Sending a new SUBSCRIBE");
753 __linphone_friend_do_subscribe(fr);
754 }else if (can_subscribe && fr->subscribe_active && !fr->subscribe){
755 linphone_friend_unsubscribe(fr);
756 }else if (!can_subscribe && fr->outsub){
757 fr->subscribe_active=FALSE;
758 sal_op_stop_refreshing(fr->outsub);
759 }
760 }
761
linphone_friend_save(LinphoneFriend * fr,LinphoneCore * lc)762 void linphone_friend_save(LinphoneFriend *fr, LinphoneCore *lc) {
763 if (!lc) return;
764 #ifdef SQLITE_STORAGE_ENABLED
765 if (lc->friends_db_file) {
766 linphone_core_store_friend_in_db(lc, fr);
767 } else {
768 linphone_core_write_friends_config(lc);
769 }
770 #else
771 linphone_core_write_friends_config(lc);
772 #endif
773 }
774
linphone_friend_apply(LinphoneFriend * fr,LinphoneCore * lc)775 void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc) {
776 LinphonePresenceModel *model;
777 const LinphoneAddress *addr = linphone_friend_get_address(fr);
778
779 if (!addr) {
780 ms_debug("No sip url defined in friend %s", linphone_friend_get_name(fr));
781 return;
782 }
783 if (!linphone_core_ready(lc)) {
784 /* lc not ready, deffering subscription */
785 fr->commit=TRUE;
786 return;
787 }
788
789 if (fr->inc_subscribe_pending) {
790 switch(fr->pol) {
791 case LinphoneSPWait:
792 model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOther, "Waiting for user acceptance");
793 linphone_friend_notify(fr, model);
794 linphone_presence_model_unref(model);
795 break;
796 case LinphoneSPAccept:
797 if (fr->lc)
798 linphone_friend_notify(fr, fr->lc->presence_model);
799 break;
800 case LinphoneSPDeny:
801 linphone_friend_notify(fr, NULL);
802 break;
803 }
804 fr->inc_subscribe_pending = FALSE;
805 }
806
807 if (fr->pol == LinphoneSPDeny && fr->insubs) {
808 linphone_friend_close_incoming_subscriptions(fr);
809 }
810
811 linphone_friend_update_subscribes(fr, linphone_core_should_subscribe_friends_only_when_registered(lc));
812
813 ms_debug("linphone_friend_apply() done.");
814 lc->bl_refresh=TRUE;
815 fr->commit=FALSE;
816 }
817
linphone_friend_edit(LinphoneFriend * fr)818 void linphone_friend_edit(LinphoneFriend *fr) {
819 if (fr && linphone_core_vcard_supported() && fr->vcard) {
820 linphone_vcard_compute_md5_hash(fr->vcard);
821 }
822 }
823
linphone_friend_done(LinphoneFriend * fr)824 void linphone_friend_done(LinphoneFriend *fr) {
825 ms_return_if_fail(fr);
826 if (!fr->lc) return;
827
828 if (fr && linphone_core_vcard_supported() && fr->vcard) {
829 if (linphone_vcard_compare_md5_hash(fr->vcard) != 0) {
830 ms_debug("vCard's md5 has changed, mark friend as dirty and clear sip addresses list cache");
831 linphone_vcard_clean_cache(fr->vcard);
832 if (fr->friend_list) {
833 fr->friend_list->dirty_friends_to_update = bctbx_list_append(fr->friend_list->dirty_friends_to_update, linphone_friend_ref(fr));
834 }
835 }
836 }
837 linphone_friend_apply(fr, fr->lc);
838 linphone_friend_save(fr, fr->lc);
839 }
840
841 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
842 #pragma GCC diagnostic push
843 #endif
844 #ifdef _MSC_VER
845 #pragma warning(disable : 4996)
846 #else
847 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
848 #endif
linphone_core_create_friend(LinphoneCore * lc)849 LinphoneFriend * linphone_core_create_friend(LinphoneCore *lc) {
850 LinphoneFriend * lf = linphone_friend_new();
851 lf->lc = lc;
852 return lf;
853 }
854
linphone_core_create_friend_with_address(LinphoneCore * lc,const char * address)855 LinphoneFriend * linphone_core_create_friend_with_address(LinphoneCore *lc, const char *address) {
856 LinphoneFriend * lf = linphone_friend_new_with_address(address);
857 if (lf)
858 lf->lc = lc;
859 return lf;
860 }
861 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
862 #pragma GCC diagnostic pop
863 #endif
864
linphone_core_add_friend(LinphoneCore * lc,LinphoneFriend * lf)865 void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) {
866 if (linphone_friend_list_add_friend(linphone_core_get_default_friend_list(lc), lf) != LinphoneFriendListOK) return;
867 if (bctbx_list_find(lc->subscribers, lf)) {
868 /*if this friend was in the pending subscriber list, now remove it from this list*/
869 lc->subscribers = bctbx_list_remove(lc->subscribers, lf);
870 linphone_friend_unref(lf);
871 }
872 }
873
linphone_core_remove_friend(LinphoneCore * lc,LinphoneFriend * lf)874 void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *lf) {
875 if (lf && lf->friend_list) {
876 if (linphone_friend_list_remove_friend(lf->friend_list, lf) == LinphoneFriendListNonExistentFriend) {
877 ms_error("linphone_core_remove_friend(): friend [%p] is not part of core's list.", lf);
878 }
879 }
880 }
881
linphone_core_update_friends_subscriptions(LinphoneCore * lc)882 void linphone_core_update_friends_subscriptions(LinphoneCore *lc) {
883 bctbx_list_t *lists = lc->friends_lists;
884 while (lists) {
885 LinphoneFriendList *list = (LinphoneFriendList *)bctbx_list_get_data(lists);
886 linphone_friend_list_update_subscriptions(list);
887 lists = bctbx_list_next(lists);
888 }
889 }
890
linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore * lc)891 bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc){
892 return lp_config_get_int(lc->config,"sip","subscribe_presence_only_when_registered",1);
893 }
894
linphone_core_send_initial_subscribes(LinphoneCore * lc)895 void linphone_core_send_initial_subscribes(LinphoneCore *lc) {
896
897 if (lc->initial_subscribes_sent) return;
898 lc->initial_subscribes_sent=TRUE;
899
900 linphone_core_update_friends_subscriptions(lc);
901 }
902
linphone_core_invalidate_friend_subscriptions(LinphoneCore * lc)903 void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc) {
904 bctbx_list_t *lists = lc->friends_lists;
905 while (lists) {
906 LinphoneFriendList *list = (LinphoneFriendList *)bctbx_list_get_data(lists);
907 linphone_friend_list_invalidate_subscriptions(list);
908 lists = bctbx_list_next(lists);
909 }
910 lc->initial_subscribes_sent=FALSE;
911 }
912
linphone_friend_set_ref_key(LinphoneFriend * lf,const char * key)913 void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key){
914 if (lf->refkey != NULL) {
915 ms_free(lf->refkey);
916 lf->refkey = NULL;
917 }
918 if (key) {
919 lf->refkey = ms_strdup(key);
920 }
921 if (lf->lc) {
922 linphone_friend_save(lf, lf->lc);
923 }
924 }
925
linphone_friend_get_ref_key(const LinphoneFriend * lf)926 const char *linphone_friend_get_ref_key(const LinphoneFriend *lf){
927 return lf->refkey;
928 }
929
linphone_core_find_friend(const LinphoneCore * lc,const LinphoneAddress * addr)930 LinphoneFriend *linphone_core_find_friend(const LinphoneCore *lc, const LinphoneAddress *addr) {
931 bctbx_list_t *lists = lc->friends_lists;
932 LinphoneFriend *lf = NULL;
933 while (lists && !lf) {
934 LinphoneFriendList *list = (LinphoneFriendList *)bctbx_list_get_data(lists);
935 lf = linphone_friend_list_find_friend_by_address(list, addr);
936 lists = bctbx_list_next(lists);
937 }
938 return lf;
939 }
940
linphone_core_get_friend_by_address(const LinphoneCore * lc,const char * uri)941 LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *uri) {
942 bctbx_list_t *lists = lc->friends_lists;
943 LinphoneFriend *lf = NULL;
944 while (lists && !lf) {
945 LinphoneFriendList *list = (LinphoneFriendList *)bctbx_list_get_data(lists);
946 lf = linphone_friend_list_find_friend_by_uri(list, uri);
947 lists = bctbx_list_next(lists);
948 }
949 return lf;
950 }
951
linphone_core_get_friend_by_ref_key(const LinphoneCore * lc,const char * key)952 LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key) {
953 bctbx_list_t *lists = lc->friends_lists;
954 LinphoneFriend *lf = NULL;
955 while (lists && !lf) {
956 LinphoneFriendList *list = (LinphoneFriendList *)bctbx_list_get_data(lists);
957 lf = linphone_friend_list_find_friend_by_ref_key(list, key);
958 lists = bctbx_list_next(lists);
959 }
960 return lf;
961 }
962
linphone_core_find_friend_by_out_subscribe(const LinphoneCore * lc,SalOp * op)963 LinphoneFriend *linphone_core_find_friend_by_out_subscribe(const LinphoneCore *lc, SalOp *op) {
964 bctbx_list_t *lists = lc->friends_lists;
965 LinphoneFriend *lf = NULL;
966 while (lists && !lf) {
967 LinphoneFriendList *list = (LinphoneFriendList *)bctbx_list_get_data(lists);
968 lf = linphone_friend_list_find_friend_by_out_subscribe(list, op);
969 lists = bctbx_list_next(lists);
970 }
971 return lf;
972 }
973
linphone_core_find_friend_by_inc_subscribe(const LinphoneCore * lc,SalOp * op)974 LinphoneFriend *linphone_core_find_friend_by_inc_subscribe(const LinphoneCore *lc, SalOp *op) {
975 bctbx_list_t *lists = lc->friends_lists;
976 LinphoneFriend *lf = NULL;
977 while (lists && !lf) {
978 LinphoneFriendList *list = (LinphoneFriendList *)bctbx_list_get_data(lists);
979 lf = linphone_friend_list_find_friend_by_inc_subscribe(list, op);
980 lists = bctbx_list_next(lists);
981 }
982 return lf;
983 }
984
985 #define key_compare(s1,s2) strcmp(s1,s2)
986
__policy_str_to_enum(const char * pol)987 LinphoneSubscribePolicy __policy_str_to_enum(const char* pol){
988 if (key_compare("accept",pol)==0){
989 return LinphoneSPAccept;
990 }
991 if (key_compare("deny",pol)==0){
992 return LinphoneSPDeny;
993 }
994 if (key_compare("wait",pol)==0){
995 return LinphoneSPWait;
996 }
997 ms_warning("Unrecognized subscribe policy: %s",pol);
998 return LinphoneSPWait;
999 }
1000
__index_to_proxy(LinphoneCore * lc,int index)1001 LinphoneProxyConfig *__index_to_proxy(LinphoneCore *lc, int index){
1002 if (index>=0) return (LinphoneProxyConfig*)bctbx_list_nth_data(lc->sip_conf.proxies,index);
1003 else return NULL;
1004 }
1005
linphone_friend_new_from_config_file(LinphoneCore * lc,int index)1006 LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int index){
1007 const char *tmp;
1008 char item[50];
1009 int a;
1010 LinphoneFriend *lf;
1011 LpConfig *config=lc->config;
1012
1013 sprintf(item,"friend_%i",index);
1014
1015 if (!lp_config_has_section(config,item)){
1016 return NULL;
1017 }
1018
1019 tmp=lp_config_get_string(config,item,"url",NULL);
1020 if (tmp==NULL) {
1021 return NULL;
1022 }
1023 lf=linphone_core_create_friend_with_address(lc, tmp);
1024 if (lf==NULL) {
1025 return NULL;
1026 }
1027 tmp=lp_config_get_string(config,item,"pol",NULL);
1028 if (tmp==NULL) linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPWait);
1029 else{
1030 linphone_friend_set_inc_subscribe_policy(lf,__policy_str_to_enum(tmp));
1031 }
1032 a=lp_config_get_int(config,item,"subscribe",0);
1033 linphone_friend_send_subscribe(lf,a);
1034 a = lp_config_get_int(config, item, "presence_received", 0);
1035 lf->presence_received = (bool_t)a;
1036
1037 linphone_friend_set_ref_key(lf,lp_config_get_string(config,item,"refkey",NULL));
1038 return lf;
1039 }
1040
__policy_enum_to_str(LinphoneSubscribePolicy pol)1041 const char *__policy_enum_to_str(LinphoneSubscribePolicy pol){
1042 switch(pol){
1043 case LinphoneSPAccept:
1044 return "accept";
1045 break;
1046 case LinphoneSPDeny:
1047 return "deny";
1048 break;
1049 case LinphoneSPWait:
1050 return "wait";
1051 break;
1052 }
1053 ms_warning("Invalid policy enum value.");
1054 return "wait";
1055 }
1056
linphone_friend_write_to_config_file(LpConfig * config,LinphoneFriend * lf,int index)1057 void linphone_friend_write_to_config_file(LpConfig *config, LinphoneFriend *lf, int index){
1058 char key[50];
1059 char *tmp;
1060 const char *refkey;
1061
1062 sprintf(key,"friend_%i",index);
1063
1064 if (lf==NULL){
1065 lp_config_clean_section(config,key);
1066 return;
1067 }
1068 if (lf->uri!=NULL){
1069 tmp=linphone_address_as_string(lf->uri);
1070 if (tmp==NULL) {
1071 return;
1072 }
1073 lp_config_set_string(config,key,"url",tmp);
1074 ms_free(tmp);
1075 }
1076 lp_config_set_string(config,key,"pol",__policy_enum_to_str(lf->pol));
1077 lp_config_set_int(config,key,"subscribe",lf->subscribe);
1078 lp_config_set_int(config, key, "presence_received", lf->presence_received);
1079
1080 refkey=linphone_friend_get_ref_key(lf);
1081 if (refkey){
1082 lp_config_set_string(config,key,"refkey",refkey);
1083 }
1084 }
1085
linphone_core_write_friends_config(LinphoneCore * lc)1086 void linphone_core_write_friends_config(LinphoneCore* lc) {
1087 bctbx_list_t *elem;
1088 int i;
1089 int store_friends;
1090
1091 if (! linphone_core_ready(lc)) return; /*dont write config when reading it !*/
1092 store_friends = lp_config_get_int(lc->config, "misc", "store_friends", 1);
1093 if (store_friends) {
1094 for (elem=linphone_core_get_default_friend_list(lc)->friends,i=0; elem!=NULL; elem=bctbx_list_next(elem),i++){
1095 linphone_friend_write_to_config_file(lc->config,(LinphoneFriend*)bctbx_list_get_data(elem),i);
1096 }
1097 linphone_friend_write_to_config_file(lc->config,NULL,i); /* set the end */
1098 }
1099 }
1100
linphone_friend_get_core(const LinphoneFriend * fr)1101 LinphoneCore *linphone_friend_get_core(const LinphoneFriend *fr){
1102 return fr->lc;
1103 }
1104
linphone_friend_ref(LinphoneFriend * lf)1105 LinphoneFriend *linphone_friend_ref(LinphoneFriend *lf) {
1106 belle_sip_object_ref(lf);
1107 return lf;
1108 }
1109
linphone_friend_unref(LinphoneFriend * lf)1110 void linphone_friend_unref(LinphoneFriend *lf) {
1111 belle_sip_object_unref(lf);
1112 }
1113
1114 /* DEPRECATED */
linphone_friend_destroy(LinphoneFriend * lf)1115 void linphone_friend_destroy(LinphoneFriend *lf) {
1116 linphone_friend_unref(lf);
1117 }
1118
linphone_friend_get_vcard(LinphoneFriend * fr)1119 LinphoneVcard* linphone_friend_get_vcard(LinphoneFriend *fr) {
1120 if (fr && linphone_core_vcard_supported()) return fr->vcard;
1121 return NULL;
1122 }
1123
linphone_friend_set_vcard(LinphoneFriend * fr,LinphoneVcard * vcard)1124 void linphone_friend_set_vcard(LinphoneFriend *fr, LinphoneVcard *vcard) {
1125 if (!fr || !linphone_core_vcard_supported()) return;
1126
1127 if (vcard) linphone_vcard_ref(vcard);
1128
1129 if (fr->vcard) linphone_vcard_unref(fr->vcard);
1130 fr->vcard = vcard;
1131 linphone_friend_save(fr, fr->lc);
1132 }
1133
linphone_friend_create_vcard(LinphoneFriend * fr,const char * name)1134 bool_t linphone_friend_create_vcard(LinphoneFriend *fr, const char *name) {
1135 LinphoneVcard *vcard = NULL;
1136 LinphoneCore *lc = NULL;
1137 bool_t skip = FALSE;
1138
1139 if (!fr || !name) {
1140 ms_error("Friend or name is null");
1141 return FALSE;
1142 }
1143 if (!linphone_core_vcard_supported()) {
1144 ms_warning("VCard support is not builtin");
1145 return FALSE;
1146 }
1147 if (fr->vcard) {
1148 ms_error("Friend already has a VCard");
1149 return FALSE;
1150 }
1151
1152 vcard = linphone_factory_create_vcard(linphone_factory_get());
1153
1154 lc = fr->lc;
1155 if (!lc && fr->friend_list) {
1156 lc = fr->friend_list->lc;
1157 }
1158 if (lc) {
1159 skip = 1 - lp_config_get_int(fr->lc->config, "misc", "store_friends", 1);
1160 linphone_vcard_set_skip_validation(vcard, skip);
1161 }
1162 linphone_vcard_set_full_name(vcard, name);
1163 linphone_friend_set_vcard(fr, vcard);
1164 linphone_vcard_unref(vcard);
1165 return TRUE;
1166 }
1167
1168 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
1169 #pragma GCC diagnostic push
1170 #endif
1171 #ifdef _MSC_VER
1172 #pragma warning(disable : 4996)
1173 #else
1174 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1175 #endif
linphone_friend_new_from_vcard(LinphoneVcard * vcard)1176 LinphoneFriend *linphone_friend_new_from_vcard(LinphoneVcard *vcard) {
1177 LinphoneFriend *fr;
1178
1179 if (!linphone_core_vcard_supported()) {
1180 ms_error("VCard support is not builtin");
1181 return NULL;
1182 }
1183 if (vcard == NULL) {
1184 ms_error("Cannot create friend from null vcard");
1185 return NULL;
1186 }
1187
1188 fr = linphone_friend_new();
1189 // Currently presence takes too much time when dealing with hundreds of friends, so I disabled it for now
1190 fr->pol = LinphoneSPDeny;
1191 fr->subscribe = FALSE;
1192 linphone_friend_set_vcard(fr, vcard);
1193 return fr;
1194 }
1195 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
1196 #pragma GCC diagnostic pop
1197 #endif
1198
1199 /*drops all references to the core and unref*/
_linphone_friend_release(LinphoneFriend * lf)1200 void _linphone_friend_release(LinphoneFriend *lf){
1201 lf->lc = NULL;
1202 _linphone_friend_release_ops(lf);
1203 linphone_friend_unref(lf);
1204 }
1205
1206 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriend);
1207
1208 BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriend, belle_sip_object_t,
1209 (belle_sip_object_destroy_t) _linphone_friend_destroy,
1210 NULL, // clone
1211 _linphone_friend_marshall,
1212 FALSE
1213 );
1214
1215 /*******************************************************************************
1216 * SQL storage related functions *
1217 ******************************************************************************/
1218
1219 #ifdef SQLITE_STORAGE_ENABLED
1220
linphone_create_friends_table(sqlite3 * db)1221 static void linphone_create_friends_table(sqlite3* db) {
1222 char* errmsg = NULL;
1223 int ret;
1224 ret = sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS friends ("
1225 "id INTEGER PRIMARY KEY AUTOINCREMENT,"
1226 "friend_list_id INTEGER,"
1227 "sip_uri TEXT,"
1228 "subscribe_policy INTEGER,"
1229 "send_subscribe INTEGER,"
1230 "ref_key TEXT,"
1231 "vCard TEXT,"
1232 "vCard_etag TEXT,"
1233 "vCard_url TEXT,"
1234 "presence_received INTEGER"
1235 ");",
1236 0, 0, &errmsg);
1237 if (ret != SQLITE_OK) {
1238 ms_error("Error in creation: %s.\n", errmsg);
1239 sqlite3_free(errmsg);
1240 }
1241
1242 ret = sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS friends_lists ("
1243 "id INTEGER PRIMARY KEY AUTOINCREMENT,"
1244 "display_name TEXT,"
1245 "rls_uri TEXT,"
1246 "uri TEXT,"
1247 "revision INTEGER"
1248 ");",
1249 0, 0, &errmsg);
1250 if (ret != SQLITE_OK) {
1251 ms_error("Error in creation: %s.\n", errmsg);
1252 sqlite3_free(errmsg);
1253 }
1254 }
1255
linphone_update_friends_table(sqlite3 * db)1256 static bool_t linphone_update_friends_table(sqlite3* db) {
1257 static sqlite3_stmt *stmt_version;
1258 int database_user_version = -1;
1259 char *errmsg = NULL;
1260
1261 if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &stmt_version, NULL) == SQLITE_OK) {
1262 while(sqlite3_step(stmt_version) == SQLITE_ROW) {
1263 database_user_version = sqlite3_column_int(stmt_version, 0);
1264 ms_debug("friends database user version = %i", database_user_version);
1265 }
1266 }
1267 sqlite3_finalize(stmt_version);
1268
1269 if (database_user_version != 3100) { // Linphone 3.10.0
1270 int ret = sqlite3_exec(db,
1271 "BEGIN TRANSACTION;\n"
1272 "ALTER TABLE friends RENAME TO temp_friends;\n"
1273 "CREATE TABLE IF NOT EXISTS friends ("
1274 "id INTEGER PRIMARY KEY AUTOINCREMENT,"
1275 "friend_list_id INTEGER,"
1276 "sip_uri TEXT,"
1277 "subscribe_policy INTEGER,"
1278 "send_subscribe INTEGER,"
1279 "ref_key TEXT,"
1280 "vCard TEXT,"
1281 "vCard_etag TEXT,"
1282 "vCard_url TEXT,"
1283 "presence_received INTEGER"
1284 ");\n"
1285 "INSERT INTO friends SELECT id, friend_list_id, sip_uri, subscribe_policy, send_subscribe, ref_key, vCard, vCard_etag, vCard_url, presence_received FROM temp_friends;\n"
1286 "DROP TABLE temp_friends;\n"
1287 "PRAGMA user_version = 3100;\n"
1288 "COMMIT;", 0, 0, &errmsg);
1289 if (ret != SQLITE_OK) {
1290 ms_error("Error altering table friends: %s.\n", errmsg);
1291 sqlite3_free(errmsg);
1292 return FALSE;
1293 }
1294 return TRUE;
1295 }
1296 return FALSE;
1297 }
1298
linphone_core_friends_storage_init(LinphoneCore * lc)1299 void linphone_core_friends_storage_init(LinphoneCore *lc) {
1300 int ret;
1301 const char *errmsg;
1302 sqlite3 *db;
1303 bctbx_list_t *friends_lists = NULL;
1304
1305 linphone_core_friends_storage_close(lc);
1306
1307 ret = _linphone_sqlite3_open(lc->friends_db_file, &db);
1308 if (ret != SQLITE_OK) {
1309 errmsg = sqlite3_errmsg(db);
1310 ms_error("Error in the opening: %s.\n", errmsg);
1311 sqlite3_close(db);
1312 return;
1313 }
1314
1315 linphone_create_friends_table(db);
1316 if (linphone_update_friends_table(db)) {
1317 // After updating schema, database need to be closed/reopenned
1318 sqlite3_close(db);
1319 _linphone_sqlite3_open(lc->friends_db_file, &db);
1320 }
1321
1322 lc->friends_db = db;
1323
1324 friends_lists = linphone_core_fetch_friends_lists_from_db(lc);
1325 if (friends_lists) {
1326 const bctbx_list_t *it;
1327 ms_warning("Replacing current default friend list by the one(s) from the database");
1328 lc->friends_lists = bctbx_list_free_with_data(lc->friends_lists, (bctbx_list_free_func)linphone_friend_list_unref);
1329
1330 for (it=friends_lists;it!=NULL;it=bctbx_list_next(it)) {
1331 LinphoneFriendList *list = (LinphoneFriendList *)bctbx_list_get_data(it);
1332 linphone_core_add_friend_list(lc, list);
1333 }
1334 friends_lists = bctbx_list_free_with_data(friends_lists, (bctbx_list_free_func)linphone_friend_list_unref);
1335 }
1336 }
1337
linphone_core_friends_storage_close(LinphoneCore * lc)1338 void linphone_core_friends_storage_close(LinphoneCore *lc) {
1339 if (lc->friends_db) {
1340 sqlite3_close(lc->friends_db);
1341 lc->friends_db = NULL;
1342 }
1343 }
1344
1345 /* DB layout:
1346 * | 0 | storage_id
1347 * | 1 | display_name
1348 * | 2 | rls_uri
1349 * | 3 | uri
1350 * | 4 | revision
1351 */
create_friend_list(void * data,int argc,char ** argv,char ** colName)1352 static int create_friend_list(void *data, int argc, char **argv, char **colName) {
1353 bctbx_list_t **list = (bctbx_list_t **)data;
1354 unsigned int storage_id = (unsigned int)atoi(argv[0]);
1355 LinphoneFriendList *lfl = linphone_core_create_friend_list(NULL);
1356
1357 lfl->storage_id = storage_id;
1358 linphone_friend_list_set_display_name(lfl, argv[1]);
1359 linphone_friend_list_set_rls_uri(lfl, argv[2]);
1360 linphone_friend_list_set_uri(lfl, argv[3]);
1361 lfl->revision = atoi(argv[4]);
1362
1363 *list = bctbx_list_append(*list, linphone_friend_list_ref(lfl));
1364 linphone_friend_list_unref(lfl);
1365 return 0;
1366 }
1367
1368 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
1369 #pragma GCC diagnostic push
1370 #endif
1371 #ifdef _MSC_VER
1372 #pragma warning(disable : 4996)
1373 #else
1374 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1375 #endif
1376 /* DB layout:
1377 * | 0 | storage_id
1378 * | 1 | friend_list_id
1379 * | 2 | sip_uri
1380 * | 3 | subscribe_policy
1381 * | 4 | send_subscribe
1382 * | 5 | ref_key
1383 * | 6 | vCard
1384 * | 7 | vCard eTag
1385 * | 8 | vCard URL
1386 * | 9 | presence_received
1387 */
create_friend(void * data,int argc,char ** argv,char ** colName)1388 static int create_friend(void *data, int argc, char **argv, char **colName) {
1389 LinphoneVcardContext *context = (LinphoneVcardContext *)data;
1390 bctbx_list_t **list = (bctbx_list_t **)linphone_vcard_context_get_user_data(context);
1391 LinphoneFriend *lf = NULL;
1392 LinphoneVcard *vcard = NULL;
1393 unsigned int storage_id = (unsigned int)atoi(argv[0]);
1394
1395 vcard = linphone_vcard_context_get_vcard_from_buffer(context, argv[6]);
1396 if (vcard) {
1397 linphone_vcard_set_etag(vcard, argv[7]);
1398 linphone_vcard_set_url(vcard, argv[8]);
1399 lf = linphone_friend_new_from_vcard(vcard);
1400 linphone_vcard_unref(vcard);
1401 }
1402 if (!lf) {
1403 lf = linphone_friend_new();
1404 if (argv[2] != NULL) {
1405 LinphoneAddress *addr = linphone_address_new(argv[2]);
1406 if (addr) {
1407 linphone_friend_set_address(lf, addr);
1408 linphone_address_unref(addr);
1409 }
1410 }
1411 }
1412 linphone_friend_set_inc_subscribe_policy(lf, atoi(argv[3]));
1413 linphone_friend_send_subscribe(lf, atoi(argv[4]));
1414 linphone_friend_set_ref_key(lf, ms_strdup(argv[5]));
1415 lf->presence_received = atoi(argv[9]);
1416 lf->storage_id = storage_id;
1417
1418 *list = bctbx_list_append(*list, linphone_friend_ref(lf));
1419 linphone_friend_unref(lf);
1420 return 0;
1421 }
1422 #if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
1423 #pragma GCC diagnostic pop
1424 #endif
1425
linphone_sql_request_friend(sqlite3 * db,const char * stmt,LinphoneVcardContext * context)1426 static int linphone_sql_request_friend(sqlite3* db, const char *stmt, LinphoneVcardContext *context) {
1427 char* errmsg = NULL;
1428 int ret;
1429 ret = sqlite3_exec(db, stmt, create_friend, context, &errmsg);
1430 if (ret != SQLITE_OK) {
1431 ms_error("linphone_sql_request: statement %s -> error sqlite3_exec(): %s.", stmt, errmsg);
1432 sqlite3_free(errmsg);
1433 }
1434 return ret;
1435 }
1436
linphone_sql_request_friends_list(sqlite3 * db,const char * stmt,bctbx_list_t ** list)1437 static int linphone_sql_request_friends_list(sqlite3* db, const char *stmt, bctbx_list_t **list) {
1438 char* errmsg = NULL;
1439 int ret;
1440 ret = sqlite3_exec(db, stmt, create_friend_list, list, &errmsg);
1441 if (ret != SQLITE_OK) {
1442 ms_error("linphone_sql_request: statement %s -> error sqlite3_exec(): %s.", stmt, errmsg);
1443 sqlite3_free(errmsg);
1444 }
1445 return ret;
1446 }
1447
linphone_sql_request_generic(sqlite3 * db,const char * stmt)1448 static int linphone_sql_request_generic(sqlite3* db, const char *stmt) {
1449 char* errmsg = NULL;
1450 int ret;
1451 ret = sqlite3_exec(db, stmt, NULL, NULL, &errmsg);
1452 if (ret != SQLITE_OK) {
1453 ms_error("linphone_sql_request: statement %s -> error sqlite3_exec(): %s.", stmt, errmsg);
1454 sqlite3_free(errmsg);
1455 }
1456 return ret;
1457 }
1458
linphone_core_store_friend_in_db(LinphoneCore * lc,LinphoneFriend * lf)1459 void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf) {
1460 if (lc && lc->friends_db) {
1461 char *buf;
1462 int store_friends = lp_config_get_int(lc->config, "misc", "store_friends", 1);
1463 LinphoneVcard *vcard = NULL;
1464 const LinphoneAddress *addr;
1465 char *addr_str = NULL;
1466
1467 if (!store_friends) {
1468 return;
1469 }
1470
1471 if (!lf || !lf->friend_list) {
1472 ms_warning("Either the friend or the friend list is null, skipping...");
1473 return;
1474 }
1475
1476 if (lf->friend_list->storage_id == 0) {
1477 ms_warning("Trying to add a friend in db, but friend list isn't, let's do that first");
1478 linphone_core_store_friends_list_in_db(lc, lf->friend_list);
1479 }
1480
1481 if (linphone_core_vcard_supported()) vcard = linphone_friend_get_vcard(lf);
1482 addr = linphone_friend_get_address(lf);
1483 if (addr != NULL) addr_str = linphone_address_as_string(addr);
1484 if (lf->storage_id > 0) {
1485 buf = sqlite3_mprintf("UPDATE friends SET friend_list_id=%u,sip_uri=%Q,subscribe_policy=%i,send_subscribe=%i,ref_key=%Q,vCard=%Q,vCard_etag=%Q,vCard_url=%Q,presence_received=%i WHERE (id = %u);",
1486 lf->friend_list->storage_id,
1487 addr_str,
1488 lf->pol,
1489 lf->subscribe,
1490 lf->refkey,
1491 vcard ? linphone_vcard_as_vcard4_string(vcard) : NULL,
1492 vcard ? linphone_vcard_get_etag(vcard) : NULL,
1493 vcard ? linphone_vcard_get_url(vcard): NULL,
1494 lf->presence_received,
1495 lf->storage_id
1496 );
1497 } else {
1498 buf = sqlite3_mprintf("INSERT INTO friends VALUES(NULL,%u,%Q,%i,%i,%Q,%Q,%Q,%Q,%i);",
1499 lf->friend_list->storage_id,
1500 addr_str,
1501 lf->pol,
1502 lf->subscribe,
1503 lf->refkey,
1504 vcard ? linphone_vcard_as_vcard4_string(vcard) : NULL,
1505 vcard ? linphone_vcard_get_etag(vcard) : NULL,
1506 vcard ? linphone_vcard_get_url(vcard) : NULL,
1507 lf->presence_received
1508 );
1509 }
1510 if (addr_str != NULL) ms_free(addr_str);
1511
1512 linphone_sql_request_generic(lc->friends_db, buf);
1513 sqlite3_free(buf);
1514
1515 if (lf->storage_id == 0) {
1516 lf->storage_id = (unsigned int)sqlite3_last_insert_rowid(lc->friends_db);
1517 }
1518 }
1519 }
1520
linphone_core_store_friends_list_in_db(LinphoneCore * lc,LinphoneFriendList * list)1521 void linphone_core_store_friends_list_in_db(LinphoneCore *lc, LinphoneFriendList *list) {
1522 if (lc && lc->friends_db) {
1523 char *buf;
1524 int store_friends = lp_config_get_int(lc->config, "misc", "store_friends", 1);
1525
1526 if (!store_friends) {
1527 return;
1528 }
1529
1530 if (list->storage_id > 0) {
1531 buf = sqlite3_mprintf("UPDATE friends_lists SET display_name=%Q,rls_uri=%Q,uri=%Q,revision=%i WHERE (id = %u);",
1532 list->display_name,
1533 list->rls_uri,
1534 list->uri,
1535 list->revision,
1536 list->storage_id
1537 );
1538 } else {
1539 buf = sqlite3_mprintf("INSERT INTO friends_lists VALUES(NULL,%Q,%Q,%Q,%i);",
1540 list->display_name,
1541 list->rls_uri,
1542 list->uri,
1543 list->revision
1544 );
1545 }
1546 linphone_sql_request_generic(lc->friends_db, buf);
1547 sqlite3_free(buf);
1548
1549 if (list->storage_id == 0) {
1550 list->storage_id = (unsigned int)sqlite3_last_insert_rowid(lc->friends_db);
1551 }
1552 }
1553 }
1554
linphone_core_remove_friend_from_db(LinphoneCore * lc,LinphoneFriend * lf)1555 void linphone_core_remove_friend_from_db(LinphoneCore *lc, LinphoneFriend *lf) {
1556 if (lc && lc->friends_db) {
1557 char *buf;
1558 if (lf->storage_id == 0) {
1559 ms_error("Friend doesn't have a storage_id !");
1560 return;
1561 }
1562
1563 buf = sqlite3_mprintf("DELETE FROM friends WHERE id = %u", lf->storage_id);
1564 linphone_sql_request_generic(lc->friends_db, buf);
1565 sqlite3_free(buf);
1566
1567 lf->storage_id = 0;
1568 }
1569 }
1570
linphone_core_remove_friends_list_from_db(LinphoneCore * lc,LinphoneFriendList * list)1571 void linphone_core_remove_friends_list_from_db(LinphoneCore *lc, LinphoneFriendList *list) {
1572 if (lc && lc->friends_db) {
1573 char *buf;
1574 if (list->storage_id == 0) {
1575 ms_error("Friends list doesn't have a storage_id !");
1576 return;
1577 }
1578
1579 buf = sqlite3_mprintf("DELETE FROM friends_lists WHERE id = %u", list->storage_id);
1580 linphone_sql_request_generic(lc->friends_db, buf);
1581 sqlite3_free(buf);
1582
1583 list->storage_id = 0;
1584 }
1585 }
1586
linphone_core_fetch_friends_from_db(LinphoneCore * lc,LinphoneFriendList * list)1587 bctbx_list_t* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list) {
1588 char *buf;
1589 uint64_t begin,end;
1590 bctbx_list_t *result = NULL;
1591 bctbx_list_t *elem = NULL;
1592
1593 if (!lc || lc->friends_db == NULL || list == NULL) {
1594 ms_warning("Either lc (or list) is NULL or friends database wasn't initialized with linphone_core_friends_storage_init() yet");
1595 return NULL;
1596 }
1597
1598 linphone_vcard_context_set_user_data(lc->vcard_context, &result);
1599
1600 buf = sqlite3_mprintf("SELECT * FROM friends WHERE friend_list_id = %u ORDER BY id", list->storage_id);
1601
1602 begin = ortp_get_cur_time_ms();
1603 linphone_sql_request_friend(lc->friends_db, buf, lc->vcard_context);
1604 end = ortp_get_cur_time_ms();
1605 ms_message("%s(): %u results fetched, completed in %i ms",__FUNCTION__, (unsigned int)bctbx_list_size(result), (int)(end-begin));
1606 sqlite3_free(buf);
1607
1608 for(elem = result; elem != NULL; elem = bctbx_list_next(elem)) {
1609 bctbx_list_t *iterator;
1610 bctbx_list_t *phone_numbers;
1611 const bctbx_list_t *addresses;
1612 LinphoneFriend *lf = (LinphoneFriend *)bctbx_list_get_data(elem);
1613 lf->lc = lc;
1614 lf->friend_list = list;
1615 if (lf->refkey) {
1616 bctbx_pair_t *pair = (bctbx_pair_t*) bctbx_pair_cchar_new(lf->refkey, linphone_friend_ref(lf));
1617 bctbx_map_cchar_insert_and_delete(list->friends_map, pair);
1618 }
1619
1620 phone_numbers = linphone_friend_get_phone_numbers(lf);
1621 iterator = phone_numbers;
1622 while (iterator) {
1623 const char *number = (const char *)bctbx_list_get_data(iterator);
1624 const char *uri = linphone_friend_phone_number_to_sip_uri(lf, number);
1625 if(uri) {
1626 bctbx_pair_t *pair = (bctbx_pair_t*) bctbx_pair_cchar_new(uri, linphone_friend_ref(lf));
1627 bctbx_map_cchar_insert_and_delete(list->friends_map_uri, pair);
1628 }
1629 iterator = bctbx_list_next(iterator);
1630 }
1631
1632 addresses = linphone_friend_get_addresses(lf);
1633 iterator = (bctbx_list_t *)addresses;
1634 while (iterator) {
1635 LinphoneAddress *lfaddr = (LinphoneAddress *)bctbx_list_get_data(iterator);
1636 char *uri = linphone_address_as_string_uri_only(lfaddr);
1637 if(uri) {
1638 bctbx_pair_t *pair = (bctbx_pair_t*) bctbx_pair_cchar_new(uri, linphone_friend_ref(lf));
1639 bctbx_map_cchar_insert_and_delete(list->friends_map_uri, pair);
1640 ms_free(uri);
1641 }
1642 iterator = bctbx_list_next(iterator);
1643 }
1644 }
1645 linphone_vcard_context_set_user_data(lc->vcard_context, NULL);
1646
1647 return result;
1648 }
1649
linphone_core_fetch_friends_lists_from_db(LinphoneCore * lc)1650 bctbx_list_t* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc) {
1651 char *buf;
1652 uint64_t begin,end;
1653 bctbx_list_t *result = NULL;
1654 bctbx_list_t *elem = NULL;
1655
1656 if (!lc || lc->friends_db == NULL) {
1657 ms_warning("Either lc is NULL or friends database wasn't initialized with linphone_core_friends_storage_init() yet");
1658 return NULL;
1659 }
1660
1661 buf = sqlite3_mprintf("SELECT * FROM friends_lists ORDER BY id");
1662
1663 begin = ortp_get_cur_time_ms();
1664 linphone_sql_request_friends_list(lc->friends_db, buf, &result);
1665 end = ortp_get_cur_time_ms();
1666 ms_message("%s(): %u results fetched, completed in %i ms",__FUNCTION__, (unsigned int)bctbx_list_size(result), (int)(end-begin));
1667 sqlite3_free(buf);
1668
1669 for(elem = result; elem != NULL; elem = bctbx_list_next(elem)) {
1670 LinphoneFriendList *lfl = (LinphoneFriendList *)bctbx_list_get_data(elem);
1671 lfl->lc = lc;
1672 lfl->friends = linphone_core_fetch_friends_from_db(lc, lfl);
1673 }
1674
1675 return result;
1676 }
1677
1678 #else
1679
linphone_core_friends_storage_init(LinphoneCore * lc)1680 void linphone_core_friends_storage_init(LinphoneCore *lc) {
1681 }
1682
linphone_core_friends_storage_close(LinphoneCore * lc)1683 void linphone_core_friends_storage_close(LinphoneCore *lc) {
1684 }
1685
linphone_core_store_friend_in_db(LinphoneCore * lc,LinphoneFriend * lf)1686 void linphone_core_store_friend_in_db(LinphoneCore *lc, LinphoneFriend *lf) {
1687 }
1688
linphone_core_store_friends_list_in_db(LinphoneCore * lc,LinphoneFriendList * list)1689 void linphone_core_store_friends_list_in_db(LinphoneCore *lc, LinphoneFriendList *list) {
1690 }
1691
linphone_core_remove_friend_from_db(LinphoneCore * lc,LinphoneFriend * lf)1692 void linphone_core_remove_friend_from_db(LinphoneCore *lc, LinphoneFriend *lf) {
1693 }
1694
linphone_core_remove_friends_list_from_db(LinphoneCore * lc,LinphoneFriendList * list)1695 void linphone_core_remove_friends_list_from_db(LinphoneCore *lc, LinphoneFriendList *list) {
1696 }
1697
linphone_core_fetch_friends_from_db(LinphoneCore * lc,LinphoneFriendList * list)1698 bctbx_list_t* linphone_core_fetch_friends_from_db(LinphoneCore *lc, LinphoneFriendList *list) {
1699 return NULL;
1700 }
1701
linphone_core_fetch_friends_lists_from_db(LinphoneCore * lc)1702 bctbx_list_t* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc) {
1703 return NULL;
1704 }
1705
1706 #endif
1707
linphone_core_set_friends_database_path(LinphoneCore * lc,const char * path)1708 void linphone_core_set_friends_database_path(LinphoneCore *lc, const char *path) {
1709 if (lc->friends_db_file){
1710 ms_free(lc->friends_db_file);
1711 lc->friends_db_file = NULL;
1712 }
1713 if (path) {
1714 lc->friends_db_file = ms_strdup(path);
1715 linphone_core_friends_storage_init(lc);
1716
1717 linphone_core_migrate_friends_from_rc_to_db(lc);
1718 }
1719 }
1720
linphone_core_get_friends_database_path(LinphoneCore * lc)1721 const char* linphone_core_get_friends_database_path(LinphoneCore *lc) {
1722 return lc->friends_db_file;
1723 }
1724
linphone_core_migrate_friends_from_rc_to_db(LinphoneCore * lc)1725 void linphone_core_migrate_friends_from_rc_to_db(LinphoneCore *lc) {
1726 LpConfig *lpc = NULL;
1727 LinphoneFriend *lf = NULL;
1728 LinphoneFriendList *lfl = linphone_core_get_default_friend_list(lc);
1729 int i;
1730 #ifndef SQLITE_STORAGE_ENABLED
1731 ms_warning("linphone has been compiled without sqlite, can't migrate friends");
1732 return;
1733 #endif
1734 if (!lc) {
1735 return;
1736 }
1737
1738 lpc = linphone_core_get_config(lc);
1739 if (!lpc) {
1740 ms_warning("this core has been started without a rc file, nothing to migrate");
1741 return;
1742 }
1743 if (lp_config_get_int(lpc, "misc", "friends_migration_done", 0) == 1) {
1744 ms_warning("the friends migration has already been done, skipping...");
1745 return;
1746 }
1747
1748 if (bctbx_list_size(linphone_friend_list_get_friends(lfl)) > 0 && lfl->storage_id == 0) {
1749 linphone_core_remove_friend_list(lc, lfl);
1750 lfl = linphone_core_create_friend_list(lc);
1751 linphone_core_add_friend_list(lc, lfl);
1752 linphone_friend_list_unref(lfl);
1753 }
1754
1755 for (i = 0; (lf = linphone_friend_new_from_config_file(lc, i)) != NULL; i++) {
1756 char friend_section[32];
1757
1758 const LinphoneAddress *addr = linphone_friend_get_address(lf);
1759 if (addr) {
1760 char *address = NULL;
1761 const char *displayName = linphone_address_get_display_name(addr);
1762 if (!displayName) displayName = linphone_address_get_username(addr);
1763
1764 address = linphone_address_as_string(addr);
1765 if (linphone_core_vcard_supported()) {
1766 if (!linphone_friend_create_vcard(lf, displayName)) {
1767 ms_warning("Couldn't create vCard for friend %s", address);
1768 } else {
1769 linphone_vcard_add_sip_address(linphone_friend_get_vcard(lf), address);
1770 linphone_address_unref(lf->uri);
1771 lf->uri = NULL;
1772 }
1773 }
1774 ms_free(address);
1775
1776 linphone_friend_list_add_friend(lfl, lf);
1777 linphone_friend_unref(lf);
1778
1779 snprintf(friend_section, sizeof(friend_section), "friend_%i", i);
1780 lp_config_clean_section(lpc, friend_section);
1781 }
1782 }
1783
1784 ms_debug("friends migration successful: %i friends migrated", i);
1785 lp_config_set_int(lpc, "misc", "friends_migration_done", 1);
1786 }
1787
linphone_friend_get_subscription_state(const LinphoneFriend * lf)1788 LinphoneSubscriptionState linphone_friend_get_subscription_state(const LinphoneFriend *lf) {
1789 return lf->out_sub_state;
1790 }
1791
linphone_friend_phone_number_to_sip_uri(LinphoneFriend * lf,const char * phone_number)1792 const char * linphone_friend_phone_number_to_sip_uri(LinphoneFriend *lf, const char *phone_number) {
1793 LinphoneFriendPhoneNumberSipUri * lfpnsu;
1794 char *normalized_number;
1795 char *full_uri;
1796 LinphoneProxyConfig *proxy_config;
1797 bctbx_list_t *iterator = lf->phone_number_sip_uri_map;
1798
1799 while (iterator) {
1800 lfpnsu = (LinphoneFriendPhoneNumberSipUri *)bctbx_list_get_data(iterator);
1801 if (strcmp(lfpnsu->number, phone_number) == 0) {
1802 /*force sip uri computation because proxy config may have changed, specially, ccc could have been added since last computation*/
1803 //free_phone_number_sip_uri(lfpnsu);
1804 if (lf->phone_number_sip_uri_map == iterator) {
1805 /*change list head if head is removed*/
1806 iterator = lf->phone_number_sip_uri_map = bctbx_list_erase_link(lf->phone_number_sip_uri_map, iterator);
1807 } else {
1808 iterator = bctbx_list_erase_link(lf->phone_number_sip_uri_map, iterator);
1809 }
1810 } else {
1811 iterator = bctbx_list_next(iterator);
1812 }
1813 }
1814
1815 proxy_config = linphone_core_get_default_proxy_config(linphone_friend_get_core(lf));
1816 if (!proxy_config) return NULL;
1817 if (strstr(phone_number, "tel:") == phone_number) phone_number += 4; /* Remove the "tel:" prefix if it is present. */
1818 normalized_number = linphone_proxy_config_normalize_phone_number(proxy_config, phone_number);
1819 if (!normalized_number) return NULL;
1820 full_uri = ms_strdup_printf("sip:%s@%s;user=phone", normalized_number, linphone_proxy_config_get_domain(proxy_config));
1821
1822 if(strcmp(normalized_number, phone_number) != 0) {
1823 char *old_uri = ms_strdup_printf("sip:%s@%s;user=phone", phone_number, linphone_proxy_config_get_domain(proxy_config));
1824 bctbx_iterator_t *it = bctbx_map_cchar_find_key(lf->friend_list->friends_map_uri, old_uri);
1825 if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(lf->friend_list->friends_map_uri))){
1826 linphone_friend_unref((LinphoneFriend*)bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it)));
1827 bctbx_map_cchar_erase(lf->friend_list->friends_map_uri, it);
1828 }
1829 bctbx_iterator_cchar_delete(it);
1830 ms_free(old_uri);
1831 }
1832
1833 if(!linphone_friend_list_find_friend_by_uri(lf->friend_list, full_uri)) {
1834 bctbx_pair_t *pair = (bctbx_pair_t*) bctbx_pair_cchar_new(full_uri, linphone_friend_ref(lf));
1835 bctbx_map_cchar_insert_and_delete(lf->friend_list->friends_map_uri, pair);
1836 }
1837
1838 ms_free(normalized_number);
1839 lfpnsu = ms_new0(LinphoneFriendPhoneNumberSipUri, 1);
1840 lfpnsu->number = ms_strdup(phone_number);
1841 lfpnsu->uri = full_uri;
1842 lf->phone_number_sip_uri_map = bctbx_list_append(lf->phone_number_sip_uri_map, lfpnsu);
1843 return full_uri;
1844 }
1845
linphone_friend_sip_uri_to_phone_number(LinphoneFriend * lf,const char * uri)1846 const char * linphone_friend_sip_uri_to_phone_number(LinphoneFriend *lf, const char *uri) {
1847 bctbx_list_t *iterator = lf->phone_number_sip_uri_map;
1848
1849 while (iterator) {
1850 LinphoneFriendPhoneNumberSipUri *lfpnsu = (LinphoneFriendPhoneNumberSipUri *)bctbx_list_get_data(iterator);
1851 if (strcmp(lfpnsu->uri, uri) == 0) return lfpnsu->number;
1852 iterator = bctbx_list_next(iterator);
1853 }
1854 return NULL;
1855 }
1856
linphone_friend_clear_presence_models(LinphoneFriend * lf)1857 void linphone_friend_clear_presence_models(LinphoneFriend *lf) {
1858 lf->presence_models = bctbx_list_free_with_data(lf->presence_models, (bctbx_list_free_func)free_friend_presence);
1859 }
1860