presence.c 70.5 KB
Newer Older
aymeric's avatar
aymeric committed
1 2
/*
linphone
3
Copyright (C) 2010-2013  Belledonne Communications SARL
aymeric's avatar
aymeric committed
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.
aymeric's avatar
aymeric committed
18 19
*/

20
#include "linphone/core.h"
aymeric's avatar
aymeric committed
21
#include "private.h"
22 23
#include "linphone/lpconfig.h"
#include "linphone/presence.h"
24

aymeric's avatar
aymeric committed
25 26 27 28 29


extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol);


30 31

struct _LinphonePresenceNote {
32
	belle_sip_object_t base;
Ghislain MARY's avatar
Ghislain MARY committed
33
	void *user_data;
34 35 36 37
	char *lang;
	char *content;
};

38
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePresenceNote);
Ghislain MARY's avatar
Ghislain MARY committed
39
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePresenceNote);
40

41
struct _LinphonePresenceService {
42
	belle_sip_object_t base;
43
	void *user_data;
44 45
	char *id;
	LinphonePresenceBasicStatus status;
46
	char *contact;
47
	bctbx_list_t *notes;				/**< A list of _LinphonePresenceNote structures. */
48
	time_t timestamp;
49 50
};

51
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePresenceService);
Ghislain MARY's avatar
Ghislain MARY committed
52
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePresenceService);
53

54
struct _LinphonePresenceActivity {
55
	belle_sip_object_t base;
Ghislain MARY's avatar
Ghislain MARY committed
56
	void *user_data;
57
	LinphonePresenceActivityType type;
58 59 60
	char *description;
};

61
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePresenceActivity);
Ghislain MARY's avatar
Ghislain MARY committed
62
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePresenceActivity);
63

64
struct _LinphonePresencePerson {
65
	belle_sip_object_t base;
66
	void *user_data;
67
	char *id;
68 69 70
	bctbx_list_t *activities;		/**< A list of _LinphonePresenceActivity structures. */
	bctbx_list_t *activities_notes;	/**< A list of _LinphonePresenceNote structures. */
	bctbx_list_t *notes;			/**< A list of _LinphonePresenceNote structures. */
71 72 73
	time_t timestamp;
};

74
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePresencePerson);
Ghislain MARY's avatar
Ghislain MARY committed
75
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePresencePerson);
76

77 78 79 80 81
/**
 * Represents the presence model as defined in RFC 4479 and RFC 4480.
 * This model is not complete. For example, it does not handle devices.
 */
struct _LinphonePresenceModel {
82
	belle_sip_object_t base;
83
	LinphoneAddress *presentity; /* "The model seeks to describe the presentity, identified by a presentity URI.*/
Ghislain MARY's avatar
Ghislain MARY committed
84
	void *user_data;
85 86 87
	bctbx_list_t *services;	/**< A list of _LinphonePresenceService structures. Also named tuples in the RFC. */
	bctbx_list_t *persons;	/**< A list of _LinphonePresencePerson structures. */
	bctbx_list_t *notes;		/**< A list of _LinphonePresenceNote structures. */
88
	bool_t is_online;
89 90
};

91
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphonePresenceModel);
Ghislain MARY's avatar
Ghislain MARY committed
92
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePresenceModel);
93

94

95 96 97 98 99 100
static const char *person_prefix = "/pidf:presence/dm:person";


/*****************************************************************************
 * PRIVATE FUNCTIONS                                                         *
 ****************************************************************************/
101 102

/* Defined in http://www.w3.org/TR/REC-xml/ */
jehan's avatar
jehan committed
103
static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz-.";
104 105

/* NameStartChar (NameChar)* */
jehan's avatar
jehan committed
106
static char presence_id_valid_start_characters[] = ":_abcdefghijklmnopqrstuvwxyz";
107 108 109 110

static char * generate_presence_id(void) {
	char id[7];
	int i;
111
	id[0] = presence_id_valid_start_characters[ortp_random() % (sizeof(presence_id_valid_start_characters)-1)];
jehan's avatar
jehan committed
112
	for (i = 1; i < 6; i++) {
113
		id[i] = presence_id_valid_characters[ortp_random() % (sizeof(presence_id_valid_characters)-1)];
114 115 116 117 118 119
	}
	id[6] = '\0';

	return ms_strdup(id);
}

120
static void presence_note_uninit(LinphonePresenceNote *note) {
121 122 123 124 125 126
	ms_free(note->content);
	if (note->lang != NULL) {
		ms_free(note->lang);
	}
}

127
static LinphonePresenceService * presence_service_new(const char *id, LinphonePresenceBasicStatus status) {
128
	LinphonePresenceService *service = belle_sip_object_new(LinphonePresenceService);
129 130 131 132
	if (id != NULL) {
		service->id = ms_strdup(id);
	}
	service->status = status;
133
	service->timestamp = time(NULL);
134 135 136
	return service;
}

137
static void presence_service_uninit(LinphonePresenceService *service) {
138 139 140
	if (service->id != NULL) {
		ms_free(service->id);
	}
141 142 143
	if (service->contact != NULL) {
		ms_free(service->contact);
	}
144 145
	bctbx_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(service->notes);
146 147
};

148
static void presence_service_set_timestamp(LinphonePresenceService *service, time_t timestamp) {
149 150 151
	service->timestamp = timestamp;
}

152
static void presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) {
153
	service->notes = bctbx_list_append(service->notes, note);
154 155
}

156
static void presence_activity_uninit(LinphonePresenceActivity *activity) {
157 158 159 160 161 162 163 164
	if (activity->description != NULL) {
		ms_free(activity->description);
	}
}

static time_t parse_timestamp(const char *timestamp) {
	struct tm ret;
	time_t seconds;
165
#if defined(LINPHONE_WINDOWS_UNIVERSAL) || defined(LINPHONE_MSC_VER_GREATER_19)
166 167 168 169
	long adjust_timezone;
#else
	time_t adjust_timezone;
#endif
170 171 172 173 174 175 176 177 178 179 180 181

	memset(&ret, 0, sizeof(ret));
	sscanf(timestamp, "%d-%d-%dT%d:%d:%d",
	       &ret.tm_year, &ret.tm_mon, &ret.tm_mday, &ret.tm_hour, &ret.tm_min, &ret.tm_sec);
	ret.tm_mon--;
	ret.tm_year -= 1900;
	ret.tm_isdst = 0;
	seconds = mktime(&ret);
	if (seconds == (time_t)-1) {
		ms_error("mktime() failed: %s", strerror(errno));
		return (time_t)-1;
	}
182
#if defined(LINPHONE_WINDOWS_UNIVERSAL) || defined(LINPHONE_MSC_VER_GREATER_19)
183 184 185 186 187
	_get_timezone(&adjust_timezone);
#else
	adjust_timezone = timezone;
#endif
	return seconds - (time_t)adjust_timezone;
188 189
}

190
char * linphone_timestamp_to_rfc3339_string(time_t timestamp) {
191 192
	char timestamp_str[22];
	struct tm *ret;
193
#ifndef _WIN32
194 195 196
	struct tm gmt;
	ret = gmtime_r(&timestamp,&gmt);
#else
197
	ret = gmtime(&timestamp);
198 199 200 201 202 203
#endif
	snprintf(timestamp_str, sizeof(timestamp_str), "%4d-%02d-%02dT%02d:%02d:%02dZ",
		 ret->tm_year + 1900, ret->tm_mon + 1, ret->tm_mday, ret->tm_hour, ret->tm_min, ret->tm_sec);
	return ms_strdup(timestamp_str);
}

204
static LinphonePresencePerson * presence_person_new(const char *id,  time_t timestamp) {
205
	LinphonePresencePerson *person = belle_sip_object_new(LinphonePresencePerson);
206 207 208
	if (id != NULL) {
		person->id = ms_strdup(id);
	}
209
	if (person->timestamp == ((time_t)-1))
210
		person->timestamp = time(NULL);
211 212
	else
		person->timestamp = timestamp;
213 214 215
	return person;
}

216
static void presence_person_uninit(LinphonePresencePerson *person) {
217 218 219
	if (person->id != NULL) {
		ms_free(person->id);
	}
220 221 222 223 224 225
	bctbx_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref);
	bctbx_list_free(person->activities);
	bctbx_list_for_each(person->activities_notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(person->activities_notes);
	bctbx_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(person->notes);
226 227
}

228
static void presence_person_add_activities_note(LinphonePresencePerson *person, LinphonePresenceNote *note) {
229
	person->activities_notes = bctbx_list_append(person->activities_notes, note);
230 231
}

232
static void presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note) {
233
	person->notes = bctbx_list_append(person->notes, note);
234 235
}

236
static int presence_model_insert_person_by_timestamp(LinphonePresencePerson *current, LinphonePresencePerson *to_insert) {
237
	return current->timestamp < to_insert->timestamp;
238 239
}

240
static void presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) {
241
	model->persons = bctbx_list_insert_sorted(model->persons, linphone_presence_person_ref(person), (bctbx_compare_func)presence_model_insert_person_by_timestamp);
242 243
}

244
static void presence_model_add_note(LinphonePresenceModel *model, LinphonePresenceNote *note) {
245
	model->notes = bctbx_list_append(model->notes, note);
246 247
}

248
static void presence_model_find_open_basic_status(LinphonePresenceService *service, LinphonePresenceBasicStatus *status) {
249 250 251 252 253
	if (service->status == LinphonePresenceBasicStatusOpen) {
		*status = LinphonePresenceBasicStatusOpen;
	}
}

254
static void presence_model_uninit(LinphonePresenceModel *model) {
255 256
	if (model->presentity)
		linphone_address_unref(model->presentity);
257 258 259 260 261 262
	bctbx_list_for_each(model->services, (MSIterateFunc)linphone_presence_service_unref);
	bctbx_list_free(model->services);
	bctbx_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_unref);
	bctbx_list_free(model->persons);
	bctbx_list_for_each(model->notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(model->notes);
263 264
}

Ghislain MARY's avatar
Ghislain MARY committed
265

266 267 268 269 270 271 272 273

/*****************************************************************************
 * HELPER FUNCTIONS TO EASE ACCESS IN MOST SIMPLER CASES                     *
 ****************************************************************************/

LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivityType acttype, const char *description) {
	LinphonePresenceModel *model = linphone_presence_model_new();
	if (model != NULL) {
274
		linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusOpen);
275
		linphone_presence_model_set_activity(model, acttype, description);
Ghislain MARY's avatar
Ghislain MARY committed
276 277 278 279
	}
	return model;
}

280 281 282
LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivityType acttype, const char *description, const char *note, const char *lang) {
	LinphonePresenceModel *model = linphone_presence_model_new();
	if (model != NULL) {
283
		linphone_presence_model_set_basic_status(model, LinphonePresenceBasicStatusOpen);
284 285 286 287
		linphone_presence_model_set_activity(model, acttype, description);
		linphone_presence_model_add_note(model, note, lang);
	}
	return model;
Ghislain MARY's avatar
Ghislain MARY committed
288 289
}

290 291 292
/* Suppose that if at least one service is open, then the model is open. */
LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model) {
	LinphonePresenceBasicStatus status = LinphonePresenceBasicStatusClosed;
293
	if (model != NULL) {
294
		bctbx_list_for_each2(model->services, (MSIterate2Func)presence_model_find_open_basic_status, &status);
295
	}
296 297 298
	return status;
}

299
LinphoneStatus linphone_presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) {
300
	LinphonePresenceService *service;
301
	int err = 0;
302 303 304

	if (model == NULL) return -1;

305
	linphone_presence_model_clear_services(model);
306
	service = linphone_presence_service_new(NULL, basic_status, NULL);
307 308
	if (service == NULL) return -1;

309 310 311
	err = linphone_presence_model_add_service(model, service);
	linphone_presence_service_unref(service);
	return err;
312 313
}

314
static void presence_service_find_newer_timestamp(LinphonePresenceService *service, time_t *timestamp) {
315 316 317 318
	if (service->timestamp > *timestamp)
		*timestamp = service->timestamp;
}

319
static void presence_person_find_newer_timestamp(LinphonePresencePerson *person, time_t *timestamp) {
320 321 322 323 324 325 326 327 328 329
	if (person->timestamp > *timestamp)
		*timestamp = person->timestamp;
}

time_t linphone_presence_model_get_timestamp(const LinphonePresenceModel *model) {
	time_t timestamp = (time_t)-1;

	if (model == NULL)
		return timestamp;

330 331
	bctbx_list_for_each2(model->services, (MSIterate2Func)presence_service_find_newer_timestamp, &timestamp);
	bctbx_list_for_each2(model->persons, (MSIterate2Func)presence_person_find_newer_timestamp, &timestamp);
332 333 334 335

	return timestamp;
}

336
static void presence_model_find_contact(LinphonePresenceService *service, char **contact) {
337 338 339 340 341 342
	if ((service->contact != NULL) && (*contact == NULL))
		*contact = service->contact;
}

char * linphone_presence_model_get_contact(const LinphonePresenceModel *model) {
	char *contact = NULL;
343
	bctbx_list_for_each2(model->services, (MSIterate2Func)presence_model_find_contact, &contact);
344 345 346 347
	if (contact == NULL) return NULL;
	return ms_strdup(contact);
}

348
LinphoneStatus linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact) {
349 350 351 352 353 354
	LinphonePresenceService *service;

	if (model == NULL) return -1;

	service = linphone_presence_model_get_nth_service(model, 0);
	if (service == NULL) {
355
		service = linphone_presence_service_new(NULL, LinphonePresenceBasicStatusClosed, NULL);
356 357
		if (service == NULL) return -1;
		linphone_presence_model_add_service(model, service);
358
	}
359 360 361 362
	return linphone_presence_service_set_contact(service, contact);
}

static void presence_model_count_activities(const LinphonePresencePerson *person, unsigned int *nb) {
363
	*nb += (unsigned int)bctbx_list_size(person->activities);
364 365 366 367 368
}

struct _get_activity_st {
	unsigned int requested_idx;
	unsigned int current_idx;
369
	LinphonePresenceActivity *activity;
370 371
};

372
static void presence_model_get_activity(const LinphonePresencePerson *person, struct _get_activity_st *st) {
373
	if (st->current_idx != (unsigned)-1) {
374
		unsigned int size = (unsigned int)bctbx_list_size(person->activities);
375
		if (st->requested_idx < (st->current_idx + size)) {
376
			st->activity = (LinphonePresenceActivity *)bctbx_list_nth_data(person->activities, st->requested_idx - st->current_idx);
377 378 379 380
			st->current_idx = (unsigned)-1;
		} else {
			st->current_idx += size;
		}
381 382 383
	}
}

384 385
LinphonePresenceActivity * linphone_presence_model_get_activity(const LinphonePresenceModel *model) {
	return linphone_presence_model_get_nth_activity(model, 0);
386 387
}

388
LinphoneStatus linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) {
389
	LinphonePresenceActivity *activity;
390
	int err = 0;
391 392 393

	if (model == NULL) return -1;

394
	linphone_presence_model_clear_activities(model);
395 396
	activity = linphone_presence_activity_new(acttype, description);
	if (activity == NULL) return -1;
397 398 399
	err = linphone_presence_model_add_activity(model, activity);
	linphone_presence_activity_unref(activity);
	return err;
400 401
}

402
unsigned int linphone_presence_model_get_nb_activities(const LinphonePresenceModel *model) {
403
	unsigned int nb = 0;
404
	bctbx_list_for_each2(model->persons, (MSIterate2Func)presence_model_count_activities, &nb);
405 406 407 408 409 410
	return nb;
}

LinphonePresenceActivity * linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx) {
	struct _get_activity_st st;

411
	if ((model == NULL) || (idx >= linphone_presence_model_get_nb_activities(model)))
412 413 414 415
		return NULL;

	memset(&st, 0, sizeof(st));
	st.requested_idx = idx;
416
	bctbx_list_for_each2(model->persons, (MSIterate2Func)presence_model_get_activity, &st);
417 418 419 420

	return st.activity;
}

421
LinphoneStatus linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivity *activity) {
422
	char *id = NULL;
423
	LinphonePresencePerson *person = NULL;
424

425
	if ((model == NULL) || (activity == NULL)) return -1;
426

427
	if (bctbx_list_size(model->persons) == 0) {
428 429 430 431 432 433 434 435
		/* There is no person in the presence model, add one. */
		id = generate_presence_id();
		person = presence_person_new(id, time(NULL));
		if (id != NULL) ms_free(id);
		if (person == NULL)
			return -1;

		presence_model_add_person(model, person);
Ghislain MARY's avatar
Ghislain MARY committed
436
		linphone_presence_person_unref(person);
437 438
	} else {
		/* Add the activity to the first person in the model. */
439
		person = (LinphonePresencePerson *)bctbx_list_nth_data(model->persons, 0);
440 441
	}

442
	linphone_presence_person_add_activity(person, activity);
443 444 445
	return 0;
}

446
LinphoneStatus linphone_presence_model_clear_activities(LinphonePresenceModel *model) {
447 448
	if (model == NULL) return -1;

449
	bctbx_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_clear_activities);
450 451 452
	return 0;
}

453 454
struct _find_note_st {
	const char *lang;
455
	LinphonePresenceNote *note;
456 457
};

458
static LinphonePresenceNote * find_presence_note_in_list(bctbx_list_t *list, const char *lang) {
459
	int i;
460
	int nb = (int)bctbx_list_size(list);
461
	for (i = 0; i < nb; i++) {
462
		LinphonePresenceNote *note = (LinphonePresenceNote *)bctbx_list_nth_data(list, i);
463 464 465 466 467 468 469 470 471 472 473
		if (lang == NULL) {
			if (note->lang == NULL) {
				return note;
			}
		} else {
			if ((note->lang != NULL) && (strcmp(lang, note->lang) == 0)) {
				return note;
			}
		}
	}

474 475 476
	return NULL;
}

477
static void find_presence_person_note(LinphonePresencePerson *person, struct _find_note_st *st) {
478 479 480 481 482 483 484 485
	/* First look for the note in the activities notes... */
	st->note = find_presence_note_in_list(person->activities_notes, st->lang);
	if (st->note != NULL) return;

	/* ... then look in the person notes. */
	st->note = find_presence_note_in_list(person->notes, st->lang);
}

486
static void find_presence_service_note(LinphonePresenceService *service, struct _find_note_st *st) {
487 488 489
	st->note = find_presence_note_in_list(service->notes, st->lang);
}

490 491
static LinphonePresenceNote * get_first_presence_note_in_list(bctbx_list_t *list) {
	return (LinphonePresenceNote *)bctbx_list_nth_data(list, 0);
492 493
}

494
static void get_first_presence_person_note(LinphonePresencePerson *person, struct _find_note_st *st) {
495 496 497 498 499
	st->note = get_first_presence_note_in_list(person->activities_notes);
	if (st->note != NULL) return;
	st->note = get_first_presence_note_in_list(person->notes);
}

500
static void get_first_presence_service_note(LinphonePresenceService *service, struct _find_note_st *st) {
501 502 503
	st->note = get_first_presence_note_in_list(service->notes);
}

504
LinphonePresenceNote * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) {
505 506 507 508 509 510 511 512
	struct _find_note_st st;

	if (model == NULL) return NULL;

	st.note = NULL;
	if (lang != NULL) {
		/* First try to find a note in the specified language exactly. */
		st.lang = lang;
513
		bctbx_list_for_each2(model->persons, (MSIterate2Func)find_presence_person_note, &st);
514
		if (st.note == NULL) {
515
			bctbx_list_for_each2(model->services, (MSIterate2Func)find_presence_service_note, &st);
516 517 518 519 520 521 522 523 524
		}
		if (st.note == NULL) {
			st.note = find_presence_note_in_list(model->notes, lang);
		}
	}

	if (st.note == NULL) {
		/* No notes in the specified language has been found, try to find one without language. */
		st.lang = NULL;
525
		bctbx_list_for_each2(model->persons, (MSIterate2Func)find_presence_person_note, &st);
526
		if (st.note == NULL) {
527
			bctbx_list_for_each2(model->services, (MSIterate2Func)find_presence_service_note, &st);
528 529 530 531 532 533 534 535
		}
		if (st.note == NULL) {
			st.note = find_presence_note_in_list(model->notes, NULL);
		}
	}

	if (st.note == NULL) {
		/* Still no result, so get the first note even if it is not in the specified language. */
536
		bctbx_list_for_each2(model->persons, (MSIterate2Func)get_first_presence_person_note, &st);
537
		if (st.note == NULL) {
538
			bctbx_list_for_each2(model->services, (MSIterate2Func)get_first_presence_service_note, &st);
539 540 541 542 543 544
		}
		if (st.note == NULL) {
			st.note = get_first_presence_note_in_list(model->notes);
		}
	}

545
	return st.note;
546 547
}

548
LinphoneStatus linphone_presence_model_add_note(LinphonePresenceModel *model, const char *note_content, const char *lang) {
549 550
	LinphonePresenceService *service;
	LinphonePresenceNote *note;
551 552 553 554 555

	if ((model == NULL) || (note_content == NULL))
		return -1;

	/* Will put the note in the first service. */
556
	service = bctbx_list_nth_data(model->services, 0);
557 558 559 560 561 562 563 564 565 566
	if (service == NULL) {
		/* If no service exists, create one. */
		service = presence_service_new(generate_presence_id(), LinphonePresenceBasicStatusClosed);
	}
	if (service == NULL)
		return -1;

	/* Search for an existing note in the specified language. */
	note = find_presence_note_in_list(service->notes, lang);
	if (note == NULL) {
567
		note = linphone_presence_note_new(note_content, lang);
568
	} else {
569
		linphone_presence_note_set_content(note, note_content);
570 571 572 573 574 575 576 577 578
	}
	if (note == NULL)
		return -1;

	presence_service_add_note(service, note);

	return 0;
}

579
static void clear_presence_person_notes(LinphonePresencePerson *person) {
580 581
	bctbx_list_for_each(person->activities_notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(person->activities_notes);
582
	person->activities_notes = NULL;
583 584
	bctbx_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(person->notes);
585 586 587
	person->notes = NULL;
}

588
static void clear_presence_service_notes(LinphonePresenceService *service) {
589 590
	bctbx_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(service->notes);
591 592 593
	service->notes = NULL;
}

594
LinphoneStatus linphone_presence_model_clear_notes(LinphonePresenceModel *model) {
595 596 597
	if (model == NULL)
		return -1;

598 599 600 601
	bctbx_list_for_each(model->persons, (MSIterateFunc)clear_presence_person_notes);
	bctbx_list_for_each(model->services, (MSIterateFunc)clear_presence_service_notes);
	bctbx_list_for_each(model->notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(model->notes);
602 603 604
	model->notes = NULL;

	return 0;
605 606
}

607 608 609 610 611
/*****************************************************************************
 * PRESENCE MODEL FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES             *
 ****************************************************************************/

LinphonePresenceModel * linphone_presence_model_new(void) {
612
	LinphonePresenceModel *model = belle_sip_object_new(LinphonePresenceModel);
613
	return model;
614 615
}

616
unsigned int linphone_presence_model_get_nb_services(const LinphonePresenceModel *model) {
617
	return (unsigned int)bctbx_list_size(model->services);
618
}
619

620
LinphonePresenceService * linphone_presence_model_get_nth_service(const LinphonePresenceModel *model, unsigned int idx) {
621
	if ((model == NULL) || (idx >= linphone_presence_model_get_nb_services(model)))
622
		return NULL;
623

624
	return (LinphonePresenceService *)bctbx_list_nth_data(model->services, idx);
625 626
}

627
LinphoneStatus linphone_presence_model_add_service(LinphonePresenceModel *model, LinphonePresenceService *service) {
628
	if ((model == NULL) || (service == NULL)) return -1;
629
	model->services = bctbx_list_append(model->services, linphone_presence_service_ref(service));
630
	return 0;
631 632
}

633
LinphoneStatus linphone_presence_model_clear_services(LinphonePresenceModel *model) {
634 635
	if (model == NULL) return -1;

636 637
	bctbx_list_for_each(model->services, (MSIterateFunc)linphone_presence_service_unref);
	bctbx_list_free(model->services);
638 639
	model->services = NULL;
	return 0;
640 641
}

642
unsigned int linphone_presence_model_get_nb_persons(const LinphonePresenceModel *model) {
643
	return (unsigned int)bctbx_list_size(model->persons);
644 645 646
}

LinphonePresencePerson * linphone_presence_model_get_nth_person(const LinphonePresenceModel *model, unsigned int idx) {
647
	if ((model == NULL) || (idx >= linphone_presence_model_get_nb_persons(model)))
648 649
		return NULL;

650
	return (LinphonePresencePerson *)bctbx_list_nth_data(model->persons, idx);
651 652
}

653
LinphoneStatus linphone_presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) {
654
	if ((model == NULL) || (person == NULL)) return -1;
655
	presence_model_add_person(model, person);
656 657 658
	return 0;
}

659
LinphoneStatus linphone_presence_model_clear_persons(LinphonePresenceModel *model) {
660 661
	if (model == NULL) return -1;

662 663
	bctbx_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_unref);
	bctbx_list_free(model->persons);
664 665 666 667
	model->persons = NULL;
	return 0;
}

668
LinphoneStatus linphone_presence_model_set_presentity(LinphonePresenceModel *model, const LinphoneAddress *presentity) {
669

670 671 672 673 674 675 676 677 678 679
	if (model->presentity) {
		linphone_address_unref(model->presentity);
		model->presentity = NULL;
	}
	if (presentity) {
		model->presentity=linphone_address_clone(presentity);
		linphone_address_clean(model->presentity);
	}
	return 0;
}
680

681 682 683
const LinphoneAddress * linphone_presence_model_get_presentity(const LinphonePresenceModel *model) {
	return model->presentity;
}
684

685 686 687 688 689 690 691 692 693 694 695 696 697
LinphoneConsolidatedPresence linphone_presence_model_get_consolidated_presence(const LinphonePresenceModel *model) {
	LinphonePresenceBasicStatus basic_status;

	if (linphone_presence_model_is_online(model)) return LinphoneConsolidatedPresenceOnline;
	basic_status = linphone_presence_model_get_basic_status(model);
	if (basic_status == LinphonePresenceBasicStatusClosed) {
		unsigned int nb_activities = linphone_presence_model_get_nb_activities(model);
		if (nb_activities == 0) return LinphoneConsolidatedPresenceOffline;
		else return LinphoneConsolidatedPresenceDoNotDisturb;
	}
	return LinphoneConsolidatedPresenceBusy;
}

698 699 700 701 702 703 704 705 706
BELLE_SIP_INSTANCIATE_VPTR(
	LinphonePresenceModel,
	belle_sip_object_t,
	presence_model_uninit, // destroy
	NULL, // clone
	NULL, // marshal
	FALSE // unown
);

707 708 709
/*****************************************************************************
 * PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES           *
 ****************************************************************************/
710

711 712 713 714 715 716 717 718 719 720
char * linphone_presence_basic_status_to_string(LinphonePresenceBasicStatus basic_status) {
	switch (basic_status) {
		case LinphonePresenceBasicStatusOpen:
			return ms_strdup("open");
		case LinphonePresenceBasicStatusClosed:
		default:
			return ms_strdup("closed");
	}
}

721
LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus basic_status, const char *contact) {
722
	LinphonePresenceService *service;
723 724 725 726 727
	char *service_id;
	if (id == NULL)
		service_id = generate_presence_id();
	else
		service_id = ms_strdup(id);
728 729
	service = presence_service_new(service_id, basic_status);
	linphone_presence_service_set_contact(service, contact);
730 731
	if (service_id != NULL)
		ms_free(service_id);
732 733
	return service;
}
734

735 736 737 738 739
char * linphone_presence_service_get_id(const LinphonePresenceService *service) {
	if (service == NULL) return NULL;
	return ms_strdup(service->id);
}

740
LinphoneStatus linphone_presence_service_set_id(LinphonePresenceService *service, const char *id) {
741 742 743 744 745 746 747 748 749 750
	if (service == NULL) return -1;
	if (service->id != NULL)
		ms_free(service->id);
	if (id == NULL)
		service->id = generate_presence_id();
	else
		service->id = ms_strdup(id);
	return 0;
}

751 752 753
LinphonePresenceBasicStatus linphone_presence_service_get_basic_status(const LinphonePresenceService *service) {
	if (service == NULL) return LinphonePresenceBasicStatusClosed;
	return service->status;
754 755
}

756
LinphoneStatus linphone_presence_service_set_basic_status(LinphonePresenceService *service, LinphonePresenceBasicStatus basic_status) {
757 758 759 760
	if (service == NULL) return -1;
	service->status = basic_status;
	return 0;
}
761

762 763 764 765
char * linphone_presence_service_get_contact(const LinphonePresenceService *service) {
	if (service->contact == NULL) return NULL;
	return ms_strdup(service->contact);
}
766

767
LinphoneStatus linphone_presence_service_set_contact(LinphonePresenceService *service, const char *contact) {
768
	if (service == NULL) return -1;
769 770 771 772 773 774
	if (service->contact != NULL)
		ms_free(service->contact);
	if (contact != NULL)
		service->contact = ms_strdup(contact);
	else
		service->contact = NULL;
775 776 777
	return 0;
}

778
unsigned int linphone_presence_service_get_nb_notes(const LinphonePresenceService *service) {
779
	return (unsigned int)bctbx_list_size(service->notes);
780 781 782
}

LinphonePresenceNote * linphone_presence_service_get_nth_note(const LinphonePresenceService *service, unsigned int idx) {
783
	if ((service == NULL) || (idx >= linphone_presence_service_get_nb_notes(service)))
784 785
		return NULL;

786
	return (LinphonePresenceNote *)bctbx_list_nth_data(service->notes, idx);
787 788
}

789
LinphoneStatus linphone_presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) {
790
	if ((service == NULL) || (note == NULL)) return -1;
791
	service->notes = bctbx_list_append(service->notes, linphone_presence_note_ref(note));
792 793 794
	return 0;
}

795
LinphoneStatus linphone_presence_service_clear_notes(LinphonePresenceService *service) {
796 797
	if (service == NULL) return -1;

798 799
	bctbx_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(service->notes);
800 801 802 803
	service->notes = NULL;
	return 0;
}

804 805 806 807 808 809 810 811 812
BELLE_SIP_INSTANCIATE_VPTR(
	LinphonePresenceService,
	belle_sip_object_t,
	presence_service_uninit, // destroy
	NULL, // clone
	NULL, // marshal
	FALSE // unown
);

813 814


815 816 817 818 819 820 821 822 823 824 825 826 827
/*****************************************************************************
 * PRESENCE PERSON FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES            *
 ****************************************************************************/

LinphonePresencePerson * linphone_presence_person_new(const char *id) {
	return presence_person_new(id, time(NULL));
}

char * linphone_presence_person_get_id(const LinphonePresencePerson *person) {
	if (person == NULL) return NULL;
	return ms_strdup(person->id);
}

828
LinphoneStatus linphone_presence_person_set_id(LinphonePresencePerson *person, const char *id) {
829 830 831 832 833 834 835 836 837 838
	if (person == NULL) return -1;
	if (person->id != NULL)
		ms_free(person->id);
	if (id == NULL)
		person->id = generate_presence_id();
	else
		person->id = ms_strdup(id);
	return 0;
}

839
unsigned int linphone_presence_person_get_nb_activities(const LinphonePresencePerson *person) {
840
	if (person == NULL) return 0;
841
	return (unsigned int)bctbx_list_size(person->activities);
842 843 844
}

LinphonePresenceActivity * linphone_presence_person_get_nth_activity(const LinphonePresencePerson *person, unsigned int idx) {
845
	if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities(person)))
846
		return NULL;
847
	return (LinphonePresenceActivity *)bctbx_list_nth_data(person->activities, idx);
848 849
}

850
LinphoneStatus linphone_presence_person_add_activity(LinphonePresencePerson *person, LinphonePresenceActivity *activity) {
851
	if ((person == NULL) || (activity == NULL)) return -1;
852
	// insert in first position since its the most recent activity!
853
	person->activities = bctbx_list_prepend(person->activities, linphone_presence_activity_ref(activity));
854 855 856
	return 0;
}

857
LinphoneStatus linphone_presence_person_clear_activities(LinphonePresencePerson *person) {
858
	if (person == NULL) return -1;
859 860
	bctbx_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref);
	bctbx_list_free(person->activities);
861 862 863 864
	person->activities = NULL;
	return 0;
}

865
unsigned int linphone_presence_person_get_nb_notes(const LinphonePresencePerson *person) {
866
	if (person == NULL) return 0;
867
	return (unsigned int)bctbx_list_size(person->notes);
868 869 870
}

LinphonePresenceNote * linphone_presence_person_get_nth_note(const LinphonePresencePerson *person, unsigned int idx) {
871
	if ((person == NULL) || (idx >= linphone_presence_person_get_nb_notes(person)))
872
		return NULL;
873
	return (LinphonePresenceNote *)bctbx_list_nth_data(person->notes, idx);
874 875
}

876
LinphoneStatus linphone_presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note) {
877
	if ((person == NULL) || (note == NULL)) return -1;
878
	person->notes = bctbx_list_append(person->notes, linphone_presence_note_ref(note));
879 880 881
	return 0;
}

882
LinphoneStatus linphone_presence_person_clear_notes(LinphonePresencePerson *person) {
883
	if (person == NULL) return -1;
884 885
	bctbx_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(person->notes);
886 887 888 889
	person->notes = NULL;
	return 0;
}

890
unsigned int linphone_presence_person_get_nb_activities_notes(const LinphonePresencePerson *person) {
891
	if (person == NULL) return 0;
892
	return (unsigned int)bctbx_list_size(person->activities_notes);
893 894 895
}

LinphonePresenceNote * linphone_presence_person_get_nth_activities_note(const LinphonePresencePerson *person, unsigned int idx) {
896
	if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities_notes(person)))
897
		return NULL;
898
	return (LinphonePresenceNote *)bctbx_list_nth_data(person->activities_notes, idx);
899 900
}

901
LinphoneStatus linphone_presence_person_add_activities_note(LinphonePresencePerson *person, LinphonePresenceNote *note) {
902
	if ((person == NULL) || (note == NULL)) return -1;
903
	person->notes = bctbx_list_append(person->activities_notes, linphone_presence_note_ref(note));
904 905 906
	return 0;
}

907
LinphoneStatus linphone_presence_person_clear_activities_notes(LinphonePresencePerson *person) {
908
	if (person == NULL) return -1;
909 910
	bctbx_list_for_each(person->activities_notes, (MSIterateFunc)linphone_presence_note_unref);
	bctbx_list_free(person->activities_notes);
911 912 913
	person->activities_notes = NULL;
	return 0;
}
914

915 916 917 918 919 920 921 922 923
BELLE_SIP_INSTANCIATE_VPTR(
	LinphonePresencePerson,
	belle_sip_object_t,
	presence_person_uninit, // destroy
	NULL, // clone
	NULL, // marshal
	FALSE // unown
)

924

925 926 927
/*****************************************************************************
 * PRESENCE ACTIVITY FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES          *
 ****************************************************************************/
928 929 930

struct _presence_activity_name_map {
	const char *name;
931
	LinphonePresenceActivityType type;
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
};

static struct _presence_activity_name_map activity_map[] = {
	{ "appointment", LinphonePresenceActivityAppointment },
	{ "away", LinphonePresenceActivityAway },
	{ "breakfast", LinphonePresenceActivityBreakfast },
	{ "busy", LinphonePresenceActivityBusy },
	{ "dinner", LinphonePresenceActivityDinner },
	{ "holiday", LinphonePresenceActivityHoliday },
	{ "in-transit", LinphonePresenceActivityInTransit },
	{ "looking-for-work", LinphonePresenceActivityLookingForWork },
	{ "lunch", LinphonePresenceActivityLunch },
	{ "meal", LinphonePresenceActivityMeal },
	{ "meeting", LinphonePresenceActivityMeeting },
	{ "on-the-phone", LinphonePresenceActivityOnThePhone },
	{ "other", LinphonePresenceActivityOther },
	{ "performance", LinphonePresenceActivityPerformance },
	{ "permanent-absence", LinphonePresenceActivityPermanentAbsence },
	{ "playing", LinphonePresenceActivityPlaying },
	{ "presentation", LinphonePresenceActivityPresentation },
	{ "shopping", LinphonePresenceActivityShopping },
	{ "sleeping", LinphonePresenceActivitySleeping },
	{ "spectator", LinphonePresenceActivitySpectator },
	{ "steering", LinphonePresenceActivitySteering },
	{ "travel", LinphonePresenceActivityTravel },
	{ "tv", LinphonePresenceActivityTV },
	{ "unknown", LinphonePresenceActivityUnknown },
	{ "vacation", LinphonePresenceActivityVacation },
	{ "working", LinphonePresenceActivityWorking },
	{ "worship", LinphonePresenceActivityWorship }
};

964
static int activity_name_to_presence_activity_type(const char *name, LinphonePresenceActivityType *acttype) {
965 966 967
	unsigned int i;
	for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) {
		if (strcmp(name, activity_map[i].name) == 0) {
968
			*acttype = activity_map[i].type;
969 970 971 972 973 974
			return 0;
		}
	}
	return -1;
}

975
static const char * presence_activity_type_to_string(LinphonePresenceActivityType acttype) {
976 977
	unsigned int i;
	for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) {
978
		if (acttype == activity_map[i].type) {
979 980 981 982 983 984
			return activity_map[i].name;
		}
	}
	return NULL;
}

985
LinphonePresenceActivity * linphone_presence_activity_new(LinphonePresenceActivityType acttype, const char *description) {
986
	LinphonePresenceActivity *act = belle_sip_object_new(LinphonePresenceActivity);
987 988 989
	act->type = acttype;
	if (description != NULL) {
		act->description = ms_strdup(description);
Ghislain MARY's avatar
Ghislain MARY committed
990
	}
991
	return act;
Ghislain MARY's avatar
Ghislain MARY committed
992 993
}

994 995 996
char * linphone_presence_activity_to_string(const LinphonePresenceActivity *activity) {
	LinphonePresenceActivityType acttype = linphone_presence_activity_get_type(activity);
	const char *description = linphone_presence_activity_get_description(activity);
997
	const char *acttype_str = acttype_str = presence_activity_type_to_string(acttype);
Ghislain MARY's avatar
Ghislain MARY committed
998 999 1000
	return ms_strdup_printf("%s%s%s", acttype_str,
				(description == NULL) ? "" : ": ",
				(description == NULL) ? "" : description);
1001 1002 1003 1004 1005 1006
}

LinphonePresenceActivityType linphone_presence_activity_get_type(const LinphonePresenceActivity *activity) {
	return activity->type;
}

1007
LinphoneStatus linphone_presence_activity_set_type(LinphonePresenceActivity *activity, LinphonePresenceActivityType acttype) {
1008 1009 1010 1011 1012
	if (activity == NULL) return -1;
	activity->type = acttype;
	return 0;
}

1013 1014 1015 1016
const char * linphone_presence_activity_get_description(const LinphonePresenceActivity *activity) {
	if (activity == NULL)
		return NULL;
	return activity->description;
1017 1018
}

1019
LinphoneStatus linphone_presence_activity_set_description(LinphonePresenceActivity *activity, const char *description) {
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
	if (activity == NULL) return -1;
	if (activity->description != NULL)
		ms_free(activity->description);
	if (description != NULL)
		activity->description = ms_strdup(description);
	else
		activity->description = NULL;
	return 0;
}

1030 1031 1032 1033 1034 1035 1036 1037
BELLE_SIP_INSTANCIATE_VPTR(
	LinphonePresenceActivity,
	belle_sip_object_t, // parent
	presence_activity_uninit, // destroy
	NULL, // clone
	NULL, // marshal
	FALSE // unown
);
1038 1039 1040 1041 1042 1043


/*****************************************************************************
 * PRESENCE NOTE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES              *
 ****************************************************************************/

1044 1045 1046 1047
LinphonePresenceNote * linphone_presence_note_new(const char *content, const char *lang) {
	LinphonePresenceNote *note;

	if (content == NULL) return NULL;
1048
	note = belle_sip_object_new(LinphonePresenceNote);
1049 1050 1051 1052 1053 1054 1055
	note->content = ms_strdup(content);
	if (lang != NULL) {
		note->lang = ms_strdup(lang);
	}
	return note;
}

1056 1057 1058 1059 1060 1061
const char * linphone_presence_note_get_content(const LinphonePresenceNote *note) {
	if (note == NULL)
		return NULL;
	return note->content;
}

1062
LinphoneStatus linphone_presence_note_set_content(LinphonePresenceNote *note, const char *content) {
1063 1064 1065 1066 1067 1068 1069 1070
	if (content == NULL) return -1;
	if (note->content != NULL) {
		ms_free(note->content);
	}
	note->content = ms_strdup(content);
	return 0;
}

1071 1072 1073 1074 1075 1076
const char * linphone_presence_note_get_lang(const LinphonePresenceNote *note) {
	if (note == NULL)
		return NULL;
	return note->lang;
}

1077
LinphoneStatus linphone_presence_note_set_lang(LinphonePresenceNote *note, const char *lang) {
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
	if (note->lang != NULL) {
		ms_free(note->lang);
		note->lang = NULL;
	}
	if (lang != NULL) {
		note->lang = ms_strdup(lang);
	}
	return 0;
}

1088 1089 1090 1091 1092 1093 1094 1095
BELLE_SIP_INSTANCIATE_VPTR(
	LinphonePresenceNote,
	belle_sip_object_t, // parent
	presence_note_uninit, // destroy
	NULL, // clone
	NULL, // marshal
	FALSE // unown
)
1096 1097 1098 1099 1100 1101 1102


/*****************************************************************************
 * PRESENCE INTERNAL FUNCTIONS FOR WRAPPERS IN OTHER PROGRAMMING LANGUAGES   *
 ****************************************************************************/

LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model) {
1103
	return (LinphonePresenceModel *)belle_sip_object_ref(model);
1104 1105 1106
}

LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model) {
1107 1108 1109
	LinphonePresenceModel *returned_model = model->base.ref > 1 ? model : NULL;
	belle_sip_object_unref(model);
	return returned_model;
1110 1111 1112 1113 1114 1115
}

void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data) {
	model->user_data = user_data;
}

1116
void * linphone_presence_model_get_user_data(const LinphonePresenceModel *model) {
1117 1118 1119 1120
	return model->user_data;
}

LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service) {
1121
	return (LinphonePresenceService *)belle_sip_object_ref(service);
1122 1123 1124
}

LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service) {
1125 1126 1127
	LinphonePresenceService *returned_service = service->base.ref > 1 ? service : NULL;
	belle_sip_object_unref(service);
	return returned_service;
1128 1129 1130 1131 1132 1133
}

void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data) {
	service->user_data = user_data;
}

1134
void * linphone_presence_service_get_user_data(const LinphonePresenceService *service) {
1135 1136 1137
	return service->user_data;
}

1138
LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person) {
1139
	return (LinphonePresencePerson *)belle_sip_object_ref(person);
1140 1141 1142
}

LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person) {
1143 1144 1145
	LinphonePresencePerson *returned_person = person->base.ref > 1 ? person : NULL;
	belle_sip_object_unref(person);
	return returned_person;
1146 1147 1148 1149 1150 1151
}

void linphone_presence_person_set_user_data(LinphonePresencePerson *person, void *user_data) {
	person->user_data = user_data;
}

1152
void * linphone_presence_person_get_user_data(const LinphonePresencePerson *person) {
1153 1154 1155
	return person->user_data;
}

1156
LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity) {
1157
	return (LinphonePresenceActivity *)belle_sip_object_ref(activity);
1158 1159 1160
}

LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity) {
1161 1162 1163
	LinphonePresenceActivity *returned_activity = activity->base.ref > 1 ? activity : NULL;
	belle_sip_object_unref(activity);
	return returned_activity;
1164 1165 1166 1167 1168 1169
}

void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data) {
	activity->user_data = user_data;
}

1170
void * linphone_presence_activity_get_user_data(const LinphonePresenceActivity *activity) {
1171 1172 1173
	return activity->user_data;
}

Ghislain MARY's avatar
Ghislain MARY committed
1174
LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note) {
1175
	return (LinphonePresenceNote *)belle_sip_object_ref(note);
Ghislain MARY's avatar
Ghislain MARY committed
1176 1177 1178
}

LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note) {
1179 1180 1181
	LinphonePresenceNote *returned_note = note->base.ref > 1 ? note : NULL;
	belle_sip_object_unref(note);
	return returned_note;
Ghislain MARY's avatar
Ghislain MARY committed
1182 1183 1184 1185 1186 1187
}

void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data) {
	note->user_data = user_data;
}

1188
void * linphone_presence_note_get_user_data(const LinphonePresenceNote *note) {
Ghislain MARY's avatar
Ghislain MARY committed
1189 1190 1191
	return note->user_data;
}

1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208


/*****************************************************************************
 * XML PRESENCE INTERNAL HANDLING                                            *
 ****************************************************************************/

static const char *service_prefix = "/pidf:presence/pidf:tuple";

static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx, LinphonePresenceService *service, unsigned int service_idx) {
	char xpath_str[MAX_XPATH_LENGTH];
	xmlXPathObjectPtr note_object;
	LinphonePresenceNote *note;
	const char *note_str;
	const char *lang;
	int i;

	snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note", service_prefix, service_idx);
1209
	note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
1210 1211 1212
	if ((note_object != NULL) && (note_object->nodesetval != NULL)) {
		for (i = 1; i <= note_object->nodesetval->nodeNr; i++) {
			snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]", service_prefix, service_idx, i);
1213
			note_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
1214 1215
			if (note_str == NULL) continue;
			snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]/@xml:lang", service_prefix, service_idx, i);
1216
			lang = linphone_get_xml_text_content(xml_ctx, xpath_str);
1217

1218
			note = linphone_presence_note_new(note_str, lang);
1219
			presence_service_add_note(service, note);
1220 1221
			if (lang != NULL) linphone_free_xml_text_content(lang);
			linphone_free_xml_text_content(note_str);
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
		}
	}
	if (note_object != NULL) xmlXPathFreeObject(note_object);

	return 0;
}

static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) {
	char xpath_str[MAX_XPATH_LENGTH];
	xmlXPathObjectPtr service_object;
	LinphonePresenceService *service;
	const char *basic_status_str;
	const char *service_id_str;
	const char *timestamp_str;
	const char *contact_str;
	LinphonePresenceBasicStatus basic_status;
	int i;

1240
	service_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, service_prefix);
1241 1242 1243
	if ((service_object != NULL) && (service_object->nodesetval != NULL)) {
		for (i = 1; i <= service_object->nodesetval->nodeNr