presence.c 65.1 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 17 18 19 20 21

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
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "linphonecore.h"
#include "private.h"
22
#include "lpconfig.h"
23
#include "linphonepresence.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 {
Ghislain MARY's avatar
Ghislain MARY committed
32 33
	void *user_data;
	int refcnt;
34 35 36 37 38
	char *lang;
	char *content;
};

struct _LinphonePresenceService {
39 40
	void *user_data;
	int refcnt;
41 42
	char *id;
	LinphonePresenceBasicStatus status;
43 44 45
	char *contact;
	MSList *notes;				/**< A list of _LinphonePresenceNote structures. */
	time_t timestamp;
46 47 48
};

struct _LinphonePresenceActivity {
Ghislain MARY's avatar
Ghislain MARY committed
49 50
	void *user_data;
	int refcnt;
51
	LinphonePresenceActivityType type;
52 53 54 55
	char *description;
};

struct _LinphonePresencePerson {
56 57
	void *user_data;
	int refcnt;
58 59 60 61 62 63 64 65 66 67 68 69
	char *id;
	MSList *activities;		/**< A list of _LinphonePresenceActivity structures. */
	MSList *activities_notes;	/**< A list of _LinphonePresenceNote structures. */
	MSList *notes;			/**< A list of _LinphonePresenceNote structures. */
	time_t timestamp;
};

/**
 * 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 {
Ghislain MARY's avatar
Ghislain MARY committed
70 71
	void *user_data;
	int refcnt;
72 73 74 75 76 77
	MSList *services;	/**< A list of _LinphonePresenceService structures. Also named tuples in the RFC. */
	MSList *persons;	/**< A list of _LinphonePresencePerson structures. */
	MSList *notes;		/**< A list of _LinphonePresenceNote structures. */
};


78 79 80 81 82 83
static const char *person_prefix = "/pidf:presence/dm:person";


/*****************************************************************************
 * PRIVATE FUNCTIONS                                                         *
 ****************************************************************************/
84

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz";

static char * generate_presence_id(void) {
	char id[7];
	int i;

	for (i = 0; i < 6; i++) {
		id[i] = presence_id_valid_characters[random() % sizeof(presence_id_valid_characters)];
	}
	id[6] = '\0';

	return ms_strdup(id);
}

static const char * presence_basic_status_to_string(LinphonePresenceBasicStatus basic_status) {
	switch (basic_status) {
		case LinphonePresenceBasicStatusOpen:
			return "open";
		case LinphonePresenceBasicStatusClosed:
		default:
			return "closed";
	}
}

109
static void presence_note_delete(LinphonePresenceNote *note) {
110 111 112 113 114 115 116
	ms_free(note->content);
	if (note->lang != NULL) {
		ms_free(note->lang);
	}
	ms_free(note);
}

117 118 119
static LinphonePresenceService * presence_service_new(const char *id, LinphonePresenceBasicStatus status) {
	LinphonePresenceService *service = ms_new0(LinphonePresenceService, 1);
	service->refcnt = 1;
120 121 122 123
	if (id != NULL) {
		service->id = ms_strdup(id);
	}
	service->status = status;
124
	service->timestamp = time(NULL);
125 126 127
	return service;
}

128
static void presence_service_delete(LinphonePresenceService *service) {
129 130 131
	if (service->id != NULL) {
		ms_free(service->id);
	}
132 133 134
	if (service->contact != NULL) {
		ms_free(service->contact);
	}
135
	ms_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref);
136
	ms_list_free(service->notes);
137 138 139
	ms_free(service);
};

140
static void presence_service_set_timestamp(LinphonePresenceService *service, time_t timestamp) {
141 142 143
	service->timestamp = timestamp;
}

144
static void presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) {
145 146 147
	service->notes = ms_list_append(service->notes, note);
}

148
static void presence_activity_delete(LinphonePresenceActivity *activity) {
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
	if (activity->description != NULL) {
		ms_free(activity->description);
	}
	ms_free(activity);
}

static time_t parse_timestamp(const char *timestamp) {
	struct tm ret;
	time_t seconds;

	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;
	}
	return seconds - timezone;
}

173
char * linphone_timestamp_to_rfc3339_string(time_t timestamp) {
174 175 176 177 178 179
	char timestamp_str[22];
	struct tm *ret;
#ifndef WIN32
	struct tm gmt;
	ret = gmtime_r(&timestamp,&gmt);
#else
180
	ret = gmtime(&timestamp);
181 182 183 184 185 186
#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);
}

187 188
static LinphonePresencePerson * presence_person_new(const char *id,  time_t timestamp) {
	LinphonePresencePerson *person = ms_new0(LinphonePresencePerson, 1);
189
	person->refcnt = 1;
190 191 192
	if (id != NULL) {
		person->id = ms_strdup(id);
	}
193
	if (person->timestamp == ((time_t)-1))
194
		person->timestamp = time(NULL);
195 196
	else
		person->timestamp = timestamp;
197 198 199
	return person;
}

200
static void presence_person_delete(LinphonePresencePerson *person) {
201 202 203
	if (person->id != NULL) {
		ms_free(person->id);
	}
204
	ms_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref);
205
	ms_list_free(person->activities);
206
	ms_list_for_each(person->activities_notes, (MSIterateFunc)linphone_presence_note_unref);
207
	ms_list_free(person->activities_notes);
208
	ms_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref);
209 210 211 212
	ms_list_free(person->notes);
	ms_free(person);
}

213
static void presence_person_add_activities_note(LinphonePresencePerson *person, LinphonePresenceNote *note) {
214 215 216
	person->activities_notes = ms_list_append(person->activities_notes, note);
}

217
static void presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note) {
218 219 220
	person->notes = ms_list_append(person->notes, note);
}

221
static void presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) {
222 223 224
	model->persons = ms_list_append(model->persons, person);
}

225
static void presence_model_add_note(LinphonePresenceModel *model, LinphonePresenceNote *note) {
226 227 228
	model->notes = ms_list_append(model->notes, note);
}

229
static void presence_model_find_open_basic_status(LinphonePresenceService *service, LinphonePresenceBasicStatus *status) {
230 231 232 233 234
	if (service->status == LinphonePresenceBasicStatusOpen) {
		*status = LinphonePresenceBasicStatusOpen;
	}
}

235
static void presence_model_delete(LinphonePresenceModel *model) {
236 237
	if (model == NULL) return;

238
	ms_list_for_each(model->services, (MSIterateFunc)linphone_presence_service_unref);
239
	ms_list_free(model->services);
240
	ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_unref);
241
	ms_list_free(model->persons);
242
	ms_list_for_each(model->notes, (MSIterateFunc)linphone_presence_note_unref);
243 244 245 246
	ms_list_free(model->notes);
	ms_free(model);
}

Ghislain MARY's avatar
Ghislain MARY committed
247

248 249 250 251 252 253 254 255 256

/*****************************************************************************
 * 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) {
		linphone_presence_model_set_activity(model, acttype, description);
Ghislain MARY's avatar
Ghislain MARY committed
257 258 259 260
	}
	return model;
}

261 262 263 264 265 266 267
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) {
		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
268 269
}

270 271 272
/* 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;
273 274 275
	if (model != NULL) {
		ms_list_for_each2(model->services, (MSIterate2Func)presence_model_find_open_basic_status, &status);
	}
276 277 278
	return status;
}

279
int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) {
280
	LinphonePresenceService *service;
281 282 283

	if (model == NULL) return -1;

284
	linphone_presence_model_clear_services(model);
285
	service = linphone_presence_service_new(NULL, basic_status, NULL);
286 287
	if (service == NULL) return -1;

288
	if (linphone_presence_model_add_service(model, service) < 0) return -1;
289 290 291
	return 0;
}

292
static void presence_service_find_newer_timestamp(LinphonePresenceService *service, time_t *timestamp) {
293 294 295 296
	if (service->timestamp > *timestamp)
		*timestamp = service->timestamp;
}

297
static void presence_person_find_newer_timestamp(LinphonePresencePerson *person, time_t *timestamp) {
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
	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;

	ms_list_for_each2(model->services, (MSIterate2Func)presence_service_find_newer_timestamp, &timestamp);
	ms_list_for_each2(model->persons, (MSIterate2Func)presence_person_find_newer_timestamp, &timestamp);

	return timestamp;
}

314
static void presence_model_find_contact(LinphonePresenceService *service, char **contact) {
315 316 317 318 319 320 321 322 323 324 325
	if ((service->contact != NULL) && (*contact == NULL))
		*contact = service->contact;
}

char * linphone_presence_model_get_contact(const LinphonePresenceModel *model) {
	char *contact = NULL;
	ms_list_for_each2(model->services, (MSIterate2Func)presence_model_find_contact, &contact);
	if (contact == NULL) return NULL;
	return ms_strdup(contact);
}

326 327 328 329 330 331 332
int linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact) {
	LinphonePresenceService *service;

	if (model == NULL) return -1;

	service = linphone_presence_model_get_nth_service(model, 0);
	if (service == NULL) {
333
		service = linphone_presence_service_new(NULL, LinphonePresenceBasicStatusClosed, NULL);
334 335
		if (service == NULL) return -1;
		linphone_presence_model_add_service(model, service);
336
	}
337 338 339 340
	return linphone_presence_service_set_contact(service, contact);
}

static void presence_model_count_activities(const LinphonePresencePerson *person, unsigned int *nb) {
341 342 343 344 345 346
	*nb += ms_list_size(person->activities);
}

struct _get_activity_st {
	unsigned int requested_idx;
	unsigned int current_idx;
347
	LinphonePresenceActivity *activity;
348 349
};

350
static void presence_model_get_activity(const LinphonePresencePerson *person, struct _get_activity_st *st) {
351 352
	unsigned int size = ms_list_size(person->activities);
	if (st->requested_idx < (st->current_idx + size)) {
353
		st->activity = (LinphonePresenceActivity *)ms_list_nth_data(person->activities, st->requested_idx - st->current_idx);
354 355 356 357 358
	} else {
		st->current_idx += size;
	}
}

359 360
LinphonePresenceActivity * linphone_presence_model_get_activity(const LinphonePresenceModel *model) {
	return linphone_presence_model_get_nth_activity(model, 0);
361 362
}

363
int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) {
364
	LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusOpen;
365
	LinphonePresenceActivity *activity;
366 367 368

	if (model == NULL) return -1;

369
	switch (acttype) {
370 371 372 373 374 375 376 377 378 379 380 381
		case LinphonePresenceActivityAppointment:
		case LinphonePresenceActivityBusy:
		case LinphonePresenceActivityMeeting:
		case LinphonePresenceActivityPermanentAbsence:
		case LinphonePresenceActivityOffline:
		case LinphonePresenceActivityWorship:
			basic_status = LinphonePresenceBasicStatusClosed;
			break;
		default:
			basic_status = LinphonePresenceBasicStatusOpen;
			break;
	}
382
	if (linphone_presence_model_set_basic_status(model, basic_status) < 0) return -1;
383
	linphone_presence_model_clear_activities(model);
384 385 386
	activity = linphone_presence_activity_new(acttype, description);
	if (activity == NULL) return -1;
	return linphone_presence_model_add_activity(model, activity);
387 388 389

}

390
unsigned int linphone_presence_model_get_nb_activities(const LinphonePresenceModel *model) {
391 392 393 394 395 396 397 398
	unsigned int nb = 0;
	ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_count_activities, &nb);
	return nb;
}

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

399
	if ((model == NULL) || (idx >= linphone_presence_model_get_nb_activities(model)))
400 401 402 403 404 405 406 407 408
		return NULL;

	memset(&st, 0, sizeof(st));
	st.requested_idx = idx;
	ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_get_activity, &st);

	return st.activity;
}

409
int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivity *activity) {
410
	char *id = NULL;
411
	LinphonePresencePerson *person = NULL;
412

413
	if ((model == NULL) || (activity == NULL)) return -1;
414 415 416 417 418 419 420 421 422 423 424 425

	if (ms_list_size(model->persons) == 0) {
		/* 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);
	} else {
		/* Add the activity to the first person in the model. */
426
		person = (LinphonePresencePerson *)ms_list_nth_data(model->persons, 0);
427 428
	}

429
	linphone_presence_person_add_activity(person, activity);
430 431 432 433 434 435
	return 0;
}

int linphone_presence_model_clear_activities(LinphonePresenceModel *model) {
	if (model == NULL) return -1;

436
	ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_clear_activities);
437 438 439
	return 0;
}

440 441
struct _find_note_st {
	const char *lang;
442
	LinphonePresenceNote *note;
443 444
};

445
static LinphonePresenceNote * find_presence_note_in_list(MSList *list, const char *lang) {
446 447 448 449 450
	int nb;
	int i;

	nb = ms_list_size(list);
	for (i = 0; i < nb; i++) {
451
		LinphonePresenceNote *note = (LinphonePresenceNote *)ms_list_nth_data(list, i);
452 453 454 455 456 457 458 459 460 461 462
		if (lang == NULL) {
			if (note->lang == NULL) {
				return note;
			}
		} else {
			if ((note->lang != NULL) && (strcmp(lang, note->lang) == 0)) {
				return note;
			}
		}
	}

463 464 465
	return NULL;
}

466
static void find_presence_person_note(LinphonePresencePerson *person, struct _find_note_st *st) {
467 468 469 470 471 472 473 474
	/* 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);
}

475
static void find_presence_service_note(LinphonePresenceService *service, struct _find_note_st *st) {
476 477 478
	st->note = find_presence_note_in_list(service->notes, st->lang);
}

479 480
static LinphonePresenceNote * get_first_presence_note_in_list(MSList *list) {
	return (LinphonePresenceNote *)ms_list_nth_data(list, 0);
481 482
}

483
static void get_first_presence_person_note(LinphonePresencePerson *person, struct _find_note_st *st) {
484 485 486 487 488
	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);
}

489
static void get_first_presence_service_note(LinphonePresenceService *service, struct _find_note_st *st) {
490 491 492
	st->note = get_first_presence_note_in_list(service->notes);
}

493
LinphonePresenceNote * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) {
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
	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;
		ms_list_for_each2(model->persons, (MSIterate2Func)find_presence_person_note, &st);
		if (st.note == NULL) {
			ms_list_for_each2(model->services, (MSIterate2Func)find_presence_service_note, &st);
		}
		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;
		ms_list_for_each2(model->persons, (MSIterate2Func)find_presence_person_note, &st);
		if (st.note == NULL) {
			ms_list_for_each2(model->services, (MSIterate2Func)find_presence_service_note, &st);
		}
		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. */
		ms_list_for_each2(model->persons, (MSIterate2Func)get_first_presence_person_note, &st);
		if (st.note == NULL) {
			ms_list_for_each2(model->services, (MSIterate2Func)get_first_presence_service_note, &st);
		}
		if (st.note == NULL) {
			st.note = get_first_presence_note_in_list(model->notes);
		}
	}

534
	return st.note;
535 536 537
}

int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *note_content, const char *lang) {
538 539
	LinphonePresenceService *service;
	LinphonePresenceNote *note;
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555

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

	/* Will put the note in the first service. */
	service = ms_list_nth_data(model->services, 0);
	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) {
Ghislain MARY's avatar
Ghislain MARY committed
556
		note = linphone_presence_note_new(note_content, lang);
557
	} else {
Ghislain MARY's avatar
Ghislain MARY committed
558
		linphone_presence_note_set_content(note, note_content);
559 560 561 562 563 564 565 566 567
	}
	if (note == NULL)
		return -1;

	presence_service_add_note(service, note);

	return 0;
}

568
static void clear_presence_person_notes(LinphonePresencePerson *person) {
569
	ms_list_for_each(person->activities_notes, (MSIterateFunc)linphone_presence_note_unref);
570 571
	ms_list_free(person->activities_notes);
	person->activities_notes = NULL;
572
	ms_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref);
573 574 575 576
	ms_list_free(person->notes);
	person->notes = NULL;
}

577
static void clear_presence_service_notes(LinphonePresenceService *service) {
578
	ms_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref);
579 580 581 582 583 584 585 586 587 588
	ms_list_free(service->notes);
	service->notes = NULL;
}

int linphone_presence_model_clear_notes(LinphonePresenceModel *model) {
	if (model == NULL)
		return -1;

	ms_list_for_each(model->persons, (MSIterateFunc)clear_presence_person_notes);
	ms_list_for_each(model->services, (MSIterateFunc)clear_presence_service_notes);
589
	ms_list_for_each(model->notes, (MSIterateFunc)linphone_presence_note_unref);
590 591 592 593
	ms_list_free(model->notes);
	model->notes = NULL;

	return 0;
594 595
}

596 597 598 599 600 601 602 603
/*****************************************************************************
 * PRESENCE MODEL FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES             *
 ****************************************************************************/

LinphonePresenceModel * linphone_presence_model_new(void) {
	LinphonePresenceModel *model = ms_new0(LinphonePresenceModel, 1);
	model->refcnt = 1;
	return model;
604 605
}

606
unsigned int linphone_presence_model_get_nb_services(const LinphonePresenceModel *model) {
607 608
	return ms_list_size(model->services);
}
609

610
LinphonePresenceService * linphone_presence_model_get_nth_service(const LinphonePresenceModel *model, unsigned int idx) {
611
	if ((model == NULL) || (idx >= linphone_presence_model_get_nb_services(model)))
612
		return NULL;
613

614
	return (LinphonePresenceService *)ms_list_nth_data(model->services, idx);
615 616
}

617 618
int linphone_presence_model_add_service(LinphonePresenceModel *model, LinphonePresenceService *service) {
	if ((model == NULL) || (service == NULL)) return -1;
619
	model->services = ms_list_append(model->services, linphone_presence_service_ref(service));
620
	return 0;
621 622
}

623 624 625 626 627 628 629
int linphone_presence_model_clear_services(LinphonePresenceModel *model) {
	if (model == NULL) return -1;

	ms_list_for_each(model->services, (MSIterateFunc)linphone_presence_service_unref);
	ms_list_free(model->services);
	model->services = NULL;
	return 0;
630 631
}

632
unsigned int linphone_presence_model_get_nb_persons(const LinphonePresenceModel *model) {
633 634 635 636
	return ms_list_size(model->persons);
}

LinphonePresencePerson * linphone_presence_model_get_nth_person(const LinphonePresenceModel *model, unsigned int idx) {
637
	if ((model == NULL) || (idx >= linphone_presence_model_get_nb_persons(model)))
638 639 640 641 642 643 644
		return NULL;

	return (LinphonePresencePerson *)ms_list_nth_data(model->persons, idx);
}

int linphone_presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) {
	if ((model == NULL) || (person == NULL)) return -1;
645
	model->persons = ms_list_append(model->persons, linphone_presence_person_ref(person));
646 647 648 649 650 651 652 653 654 655 656 657
	return 0;
}

int linphone_presence_model_clear_persons(LinphonePresenceModel *model) {
	if (model == NULL) return -1;

	ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_unref);
	ms_list_free(model->persons);
	model->persons = NULL;
	return 0;
}

658

659

660 661 662
/*****************************************************************************
 * PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES           *
 ****************************************************************************/
663

664
LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus basic_status, const char *contact) {
665
	LinphonePresenceService *service;
666 667 668 669 670
	char *service_id;
	if (id == NULL)
		service_id = generate_presence_id();
	else
		service_id = ms_strdup(id);
671 672
	service = presence_service_new(service_id, basic_status);
	linphone_presence_service_set_contact(service, contact);
673 674
	if (service_id != NULL)
		ms_free(service_id);
675 676
	return service;
}
677

678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
char * linphone_presence_service_get_id(const LinphonePresenceService *service) {
	if (service == NULL) return NULL;
	return ms_strdup(service->id);
}

int linphone_presence_service_set_id(LinphonePresenceService *service, const char *id) {
	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;
}

694 695 696
LinphonePresenceBasicStatus linphone_presence_service_get_basic_status(const LinphonePresenceService *service) {
	if (service == NULL) return LinphonePresenceBasicStatusClosed;
	return service->status;
697 698
}

699 700 701 702 703
int linphone_presence_service_set_basic_status(LinphonePresenceService *service, LinphonePresenceBasicStatus basic_status) {
	if (service == NULL) return -1;
	service->status = basic_status;
	return 0;
}
704

705 706 707 708
char * linphone_presence_service_get_contact(const LinphonePresenceService *service) {
	if (service->contact == NULL) return NULL;
	return ms_strdup(service->contact);
}
709

710
int linphone_presence_service_set_contact(LinphonePresenceService *service, const char *contact) {
711
	if (service == NULL) return -1;
712 713 714 715 716 717
	if (service->contact != NULL)
		ms_free(service->contact);
	if (contact != NULL)
		service->contact = ms_strdup(contact);
	else
		service->contact = NULL;
718 719 720
	return 0;
}

721
unsigned int linphone_presence_service_get_nb_notes(const LinphonePresenceService *service) {
722 723 724 725
	return ms_list_size(service->notes);
}

LinphonePresenceNote * linphone_presence_service_get_nth_note(const LinphonePresenceService *service, unsigned int idx) {
726
	if ((service == NULL) || (idx >= linphone_presence_service_get_nb_notes(service)))
727 728 729 730 731
		return NULL;

	return (LinphonePresenceNote *)ms_list_nth_data(service->notes, idx);
}

Ghislain MARY's avatar
Ghislain MARY committed
732
int linphone_presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) {
733
	if ((service == NULL) || (note == NULL)) return -1;
734
	service->notes = ms_list_append(service->notes, linphone_presence_note_ref(note));
735 736 737 738 739 740 741 742 743 744 745 746
	return 0;
}

int linphone_presence_service_clear_notes(LinphonePresenceService *service) {
	if (service == NULL) return -1;

	ms_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref);
	ms_list_free(service->notes);
	service->notes = NULL;
	return 0;
}

747 748


749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
/*****************************************************************************
 * 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);
}

int linphone_presence_person_set_id(LinphonePresencePerson *person, const char *id) {
	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;
}

773
unsigned int linphone_presence_person_get_nb_activities(const LinphonePresencePerson *person) {
774 775 776 777 778
	if (person == NULL) return 0;
	return ms_list_size(person->activities);
}

LinphonePresenceActivity * linphone_presence_person_get_nth_activity(const LinphonePresencePerson *person, unsigned int idx) {
779
	if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities(person)))
780 781 782 783 784 785
		return NULL;
	return (LinphonePresenceActivity *)ms_list_nth_data(person->activities, idx);
}

int linphone_presence_person_add_activity(LinphonePresencePerson *person, LinphonePresenceActivity *activity) {
	if ((person == NULL) || (activity == NULL)) return -1;
786
	person->activities = ms_list_append(person->activities, linphone_presence_activity_ref(activity));
787 788 789 790 791 792 793 794 795 796 797
	return 0;
}

int linphone_presence_person_clear_activities(LinphonePresencePerson *person) {
	if (person == NULL) return -1;
	ms_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref);
	ms_list_free(person->activities);
	person->activities = NULL;
	return 0;
}

798
unsigned int linphone_presence_person_get_nb_notes(const LinphonePresencePerson *person) {
799 800 801 802 803
	if (person == NULL) return 0;
	return ms_list_size(person->notes);
}

LinphonePresenceNote * linphone_presence_person_get_nth_note(const LinphonePresencePerson *person, unsigned int idx) {
804
	if ((person == NULL) || (idx >= linphone_presence_person_get_nb_notes(person)))
805 806 807 808 809 810
		return NULL;
	return (LinphonePresenceNote *)ms_list_nth_data(person->notes, idx);
}

int linphone_presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note) {
	if ((person == NULL) || (note == NULL)) return -1;
811
	person->notes = ms_list_append(person->notes, linphone_presence_note_ref(note));
812 813 814 815 816 817 818 819 820 821 822
	return 0;
}

int linphone_presence_person_clear_notes(LinphonePresencePerson *person) {
	if (person == NULL) return -1;
	ms_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref);
	ms_list_free(person->notes);
	person->notes = NULL;
	return 0;
}

823
unsigned int linphone_presence_person_get_nb_activities_notes(const LinphonePresencePerson *person) {
824 825 826 827 828
	if (person == NULL) return 0;
	return ms_list_size(person->activities_notes);
}

LinphonePresenceNote * linphone_presence_person_get_nth_activities_note(const LinphonePresencePerson *person, unsigned int idx) {
829
	if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities_notes(person)))
830 831 832 833 834 835
		return NULL;
	return (LinphonePresenceNote *)ms_list_nth_data(person->activities_notes, idx);
}

int linphone_presence_person_add_activities_note(LinphonePresencePerson *person, LinphonePresenceNote *note) {
	if ((person == NULL) || (note == NULL)) return -1;
836
	person->notes = ms_list_append(person->activities_notes, linphone_presence_note_ref(note));
837 838 839 840 841 842 843 844 845 846
	return 0;
}

int linphone_presence_person_clear_activities_notes(LinphonePresencePerson *person) {
	if (person == NULL) return -1;
	ms_list_for_each(person->activities_notes, (MSIterateFunc)linphone_presence_note_unref);
	ms_list_free(person->activities_notes);
	person->activities_notes = NULL;
	return 0;
}
847 848


849 850 851
/*****************************************************************************
 * PRESENCE ACTIVITY FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES          *
 ****************************************************************************/
852 853 854

struct _presence_activity_name_map {
	const char *name;
855
	LinphonePresenceActivityType type;
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
};

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

888
static int activity_name_to_presence_activity_type(const char *name, LinphonePresenceActivityType *acttype) {
889 890 891
	unsigned int i;
	for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) {
		if (strcmp(name, activity_map[i].name) == 0) {
892
			*acttype = activity_map[i].type;
893 894 895 896 897 898
			return 0;
		}
	}
	return -1;
}

899
static const char * presence_activity_type_to_string(LinphonePresenceActivityType acttype) {
900 901
	unsigned int i;
	for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) {
902
		if (acttype == activity_map[i].type) {
903 904 905 906 907 908
			return activity_map[i].name;
		}
	}
	return NULL;
}

909 910 911 912 913 914
LinphonePresenceActivity * linphone_presence_activity_new(LinphonePresenceActivityType acttype, const char *description) {
	LinphonePresenceActivity *act = ms_new0(LinphonePresenceActivity, 1);
	act->refcnt = 1;
	act->type = acttype;
	if (description != NULL) {
		act->description = ms_strdup(description);
Ghislain MARY's avatar
Ghislain MARY committed
915
	}
916
	return act;
Ghislain MARY's avatar
Ghislain MARY committed
917 918
}

919 920 921 922 923 924 925 926 927 928 929 930
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);
	const char *acttype_str;

	if (acttype == LinphonePresenceActivityOffline)
		acttype_str = "offline";
	else if (acttype == LinphonePresenceActivityOnline)
		acttype_str = "online";
	else
		acttype_str = presence_activity_type_to_string(acttype);

Ghislain MARY's avatar
Ghislain MARY committed
931 932 933
	return ms_strdup_printf("%s%s%s", acttype_str,
				(description == NULL) ? "" : ": ",
				(description == NULL) ? "" : description);
934 935 936 937 938 939 940 941
}

LinphonePresenceActivityType linphone_presence_activity_get_type(const LinphonePresenceActivity *activity) {
	if (activity == NULL)
		return LinphonePresenceActivityOffline;
	return activity->type;
}

942 943 944 945 946 947
int linphone_presence_activity_set_type(LinphonePresenceActivity *activity, LinphonePresenceActivityType acttype) {
	if (activity == NULL) return -1;
	activity->type = acttype;
	return 0;
}

948 949 950 951
const char * linphone_presence_activity_get_description(const LinphonePresenceActivity *activity) {
	if (activity == NULL)
		return NULL;
	return activity->description;
952 953
}

954 955 956 957 958 959 960 961 962 963 964
int linphone_presence_activity_set_description(LinphonePresenceActivity *activity, const char *description) {
	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;
}

965 966 967 968 969 970


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

Ghislain MARY's avatar
Ghislain MARY committed
971 972 973 974 975 976 977 978 979 980 981 982 983
LinphonePresenceNote * linphone_presence_note_new(const char *content, const char *lang) {
	LinphonePresenceNote *note;

	if (content == NULL) return NULL;
	note = ms_new0(LinphonePresenceNote, 1);
	note->refcnt = 1;
	note->content = ms_strdup(content);
	if (lang != NULL) {
		note->lang = ms_strdup(lang);
	}
	return note;
}

984 985 986 987 988 989
const char * linphone_presence_note_get_content(const LinphonePresenceNote *note) {
	if (note == NULL)
		return NULL;
	return note->content;
}

Ghislain MARY's avatar
Ghislain MARY committed
990 991 992 993 994 995 996 997 998
int linphone_presence_note_set_content(LinphonePresenceNote *note, const char *content) {
	if (content == NULL) return -1;
	if (note->content != NULL) {
		ms_free(note->content);
	}
	note->content = ms_strdup(content);
	return 0;
}

999 1000 1001 1002 1003 1004
const char * linphone_presence_note_get_lang(const LinphonePresenceNote *note) {
	if (note == NULL)
		return NULL;
	return note->lang;
}

Ghislain MARY's avatar
Ghislain MARY committed
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
int linphone_presence_note_set_lang(LinphonePresenceNote *note, const char *lang) {
	if (note->lang != NULL) {
		ms_free(note->lang);
		note->lang = NULL;
	}
	if (lang != NULL) {
		note->lang = ms_strdup(lang);
	}
	return 0;
}

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065


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

LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model) {
	model->refcnt++;
	return model;
}

LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model) {
	model->refcnt--;
	if (model->refcnt == 0) {
		presence_model_delete(model);
		return NULL;
	}
	return model;
}

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

void * linphone_presence_model_get_user_data(LinphonePresenceModel *model) {
	return model->user_data;
}

LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service) {
	service->refcnt++;
	return service;
}

LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service) {
	service->refcnt--;
	if (service->refcnt == 0) {
		presence_service_delete(service);
		return NULL;
	}
	return service;
}

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

void * linphone_presence_service_get_user_data(LinphonePresenceService *service) {
	return service->user_data;
}

1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person) {
	person->refcnt++;
	return person;
}

LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person) {
	person->refcnt--;
	if (person->refcnt == 0) {
		presence_person_delete(person);
		return NULL;
	}
	return person;
}

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

void * linphone_presence_person_get_user_data(LinphonePresencePerson *person) {
	return person->user_data;
}

1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity) {
	activity->refcnt++;
	return activity;
}

LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity) {
	activity->refcnt--;
	if (activity->refcnt == 0) {
		presence_activity_delete(activity);
		return NULL;
	}
	return activity;
}

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

void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity) {
	return activity->user_data;
}

Ghislain MARY's avatar
Ghislain MARY committed
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note) {
	note->refcnt++;
	return note;
}

LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note) {
	note->refcnt--;
	if (note->refcnt == 0) {
		presence_note_delete(note);
		return NULL;
	}
	return note;
}

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

void * linphone_presence_note_get_user_data(LinphonePresenceNote *note) {
	return note->user_data;
}

1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144