event.c 20.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
linphone
Copyright (C) 2000 - 2010 Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 19
*/

Ghislain MARY's avatar
Ghislain MARY committed
20
#include "linphone/event.h"
21
#include "linphone/lpconfig.h"
22
#include "sal/event-op.h"
23

24 25
#include "c-wrapper/c-wrapper.h"

26 27 28
// TODO: From coreapi. Remove me later.
#include "private.h"

29
using namespace LinphonePrivate;
30

31 32 33 34 35 36 37 38 39 40 41
const char * linphone_subscription_dir_to_string(LinphoneSubscriptionDir dir){
	switch(dir){
		case LinphoneSubscriptionIncoming:
			return "LinphoneSubscriptionIncoming";
		case LinphoneSubscriptionOutgoing:
			return "LinphoneSubscriptionOutgoing";
		case LinphoneSubscriptionInvalidDir:
			return "LinphoneSubscriptionInvalidDir";
	}
	return "INVALID";
}
42 43 44 45 46 47 48 49 50 51 52

LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss){
	switch(ss){
		case SalSubscribeNone: return LinphoneSubscriptionNone;
		case SalSubscribePending: return LinphoneSubscriptionPending;
		case SalSubscribeTerminated: return LinphoneSubscriptionTerminated;
		case SalSubscribeActive: return LinphoneSubscriptionActive;
	}
	return LinphoneSubscriptionNone;
}

53 54 55 56
const char *linphone_subscription_state_to_string(LinphoneSubscriptionState state){
	switch(state){
		case LinphoneSubscriptionNone: return "LinphoneSubscriptionNone";
		case LinphoneSubscriptionIncomingReceived: return "LinphoneSubscriptionIncomingReceived";
57
		case LinphoneSubscriptionOutgoingProgress: return "LinphoneSubscriptionOutgoingProgress";
58 59 60 61
		case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending";
		case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive";
		case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated";
		case LinphoneSubscriptionError: return "LinphoneSubscriptionError";
62
		case LinphoneSubscriptionExpiring: return "LinphoneSubscriptionExpiring";
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
	}
	return NULL;
}

LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishState state){
	switch(state){
		case LinphonePublishNone: return "LinphonePublishNone";
		case LinphonePublishProgress: return "LinphonePublishProgress";
		case LinphonePublishOk: return "LinphonePublishOk";
		case LinphonePublishError: return "LinphonePublishError";
		case LinphonePublishCleared: return "LinphonePublishCleared";
		case LinphonePublishExpiring: return "LinphonePublishExpiring";
	}
	return NULL;
}

79 80 81 82 83 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 109 110 111 112 113 114 115 116 117 118

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneEventCbs);

BELLE_SIP_INSTANCIATE_VPTR(LinphoneEventCbs, belle_sip_object_t,
	NULL, // destroy
	NULL, // clone
	NULL, // marshal
	FALSE
);

static LinphoneEventCbs *linphone_event_cbs_new(void) {
	return belle_sip_object_new(LinphoneEventCbs);
}

LinphoneEventCbs *linphone_event_cbs_ref(LinphoneEventCbs *cbs) {
	belle_sip_object_ref(cbs);
	return cbs;
}

void linphone_event_cbs_unref(LinphoneEventCbs *cbs) {
	belle_sip_object_unref(cbs);
}

void *linphone_event_cbs_get_user_data(const LinphoneEventCbs *cbs) {
	return cbs->user_data;
}

void linphone_event_cbs_set_user_data(LinphoneEventCbs *cbs, void *ud) {
	cbs->user_data = ud;
}

LinphoneEventCbsNotifyResponseCb linphone_event_cbs_get_notify_response(const LinphoneEventCbs *cbs) {
	return cbs->notify_response_cb;
}

void linphone_event_cbs_set_notify_response(LinphoneEventCbs *cbs, LinphoneEventCbsNotifyResponseCb cb) {
	cbs->notify_response_cb = cb;
}


119 120
static void linphone_event_release(LinphoneEvent *lev){
	if (lev->op) {
121
		/*this will stop the refresher*/
122
		lev->op->stopRefreshing();
123 124 125 126
	}
	linphone_event_unref(lev);
}

127
static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, LinphonePrivate::SalEventOp *op){
128
	LinphoneEvent *lev=belle_sip_object_new(LinphoneEvent);
129
	lev->callbacks = linphone_event_cbs_new();
130 131
	lev->lc=lc;
	lev->dir=dir;
132
	lev->op=op;
Simon Morlat's avatar
Simon Morlat committed
133
	lev->name=ms_strdup(name);
134
	if (strcmp(lev->name, "conference") == 0)
135
		lev->internal = TRUE;
136
	lev->op->setUserPointer(lev);
137 138 139
	return lev;
}

140
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires){
141
	LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, new SalSubscribeOp(lc->sal));
142
	lev->expires=expires;
143 144 145
	return lev;
}

146
static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalEventOp *op, LinphoneSubscriptionDir dir, const char *name, bool_t is_out_of_dialog){
147
	LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, op);
148
	lev->is_out_of_dialog_op=is_out_of_dialog;
149 150
	return lev;
}
Simon Morlat's avatar
Simon Morlat committed
151

152
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalEventOp *op, LinphoneSubscriptionDir dir, const char *name) {
153 154
	return linphone_event_new_with_op_base(lc,op,dir,name,FALSE);
}
Simon Morlat's avatar
Simon Morlat committed
155

156
LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalEventOp *op, LinphoneSubscriptionDir dir, const char *name) {
157 158
	return linphone_event_new_with_op_base(lc,op,dir,name,TRUE);
}
Simon Morlat's avatar
Simon Morlat committed
159

160 161 162 163 164 165 166 167
void linphone_event_set_internal(LinphoneEvent *lev, bool_t internal) {
	lev->internal = internal;
}

bool_t linphone_event_is_internal(LinphoneEvent *lev) {
	return lev->internal;
}

168
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){
169 170 171
	if (lev->subscription_state!=state){
		ms_message("LinphoneEvent [%p] moving to subscription state %s",lev,linphone_subscription_state_to_string(state));
		lev->subscription_state=state;
172
		linphone_core_notify_subscription_state_changed(lev->lc,lev,state);
173
		if (state==LinphoneSubscriptionTerminated || state == LinphoneSubscriptionError){
174
			linphone_event_release(lev);
175
		}
176 177 178
	}
}

179 180
void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state){
	if (lev->publish_state!=state){
181 182 183 184 185 186
		ms_message(
			"LinphoneEvent [%p] moving from [%s] to publish state %s",
			lev,
			linphone_publish_state_to_string(lev->publish_state),
			linphone_publish_state_to_string(state)
		);
187
		lev->publish_state=state;
188
		linphone_core_notify_publish_state_changed(lev->lc,lev,state);
Simon Morlat's avatar
Simon Morlat committed
189
		switch(state){
190
			case LinphonePublishNone: /*this state is probably trigered by a network state change to DOWN, we should release the op*/
Simon Morlat's avatar
Simon Morlat committed
191
			case LinphonePublishCleared:
192
				linphone_event_release(lev);
Simon Morlat's avatar
Simon Morlat committed
193 194
				break;
			case LinphonePublishOk:
195
				if (lev->oneshot) linphone_event_release(lev);
196
				break;
Simon Morlat's avatar
Simon Morlat committed
197
			case LinphonePublishError:
198
				linphone_event_release(lev);
Simon Morlat's avatar
Simon Morlat committed
199 200 201 202 203
				break;
			case LinphonePublishProgress:
			case LinphonePublishExpiring:
				/*nothing special to do*/
				break;
204
		}
205

206 207 208 209 210 211 212
	}
}

LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){
	return lev->publish_state;
}

213
const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev){
214 215 216
	if (!lev->ei) ((LinphoneEvent*)lev)->ei = linphone_error_info_new();
	linphone_error_info_from_sal_op(lev->ei, lev->op);
	return lev->ei;
217 218 219
}

LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){
220
	return linphone_error_info_get_reason(linphone_event_get_error_info(lev));
221 222
}

223 224
LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
	LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event, expires);
225
	linphone_configure_op(lc,lev->op,resource,NULL,TRUE);
226
	lev->op->setManualRefresherMode(!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1));
227 228 229
	return lev;
}

230 231 232 233
LinphoneEvent *linphone_core_create_notify(LinphoneCore *lc, const LinphoneAddress *resource, const char *event){
	LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionIncoming, event, -1);
	linphone_configure_op(lc,lev->op,resource,NULL,TRUE);
	lev->subscription_state = LinphoneSubscriptionIncomingReceived;
234
	lev->op->setEvent(event);
235 236 237 238
	lev->is_out_of_dialog_op = TRUE;
	return lev;
}

239 240 241 242 243
LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
	LinphoneEvent *lev=linphone_core_create_subscribe(lc,resource,event,expires);
	linphone_event_send_subscribe(lev,body);
	return lev;
}
244

245
LinphoneStatus linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
246
	SalBodyHandler *body_handler;
247
	int err;
248

249 250 251 252
	if (lev->dir!=LinphoneSubscriptionOutgoing){
		ms_error("linphone_event_send_subscribe(): cannot send or update something that is not an outgoing subscription.");
		return -1;
	}
253 254 255
	switch (lev->subscription_state){
		case LinphoneSubscriptionIncomingReceived:
		case LinphoneSubscriptionTerminated:
256
		case LinphoneSubscriptionOutgoingProgress:
257
			ms_error("linphone_event_send_subscribe(): cannot update subscription while in state [%s]", linphone_subscription_state_to_string(lev->subscription_state));
258 259
			return -1;
		break;
260
		case LinphoneSubscriptionNone:
261 262 263 264 265 266
		case LinphoneSubscriptionActive:
		case LinphoneSubscriptionExpiring:
		case LinphoneSubscriptionError:
		case LinphoneSubscriptionPending:
			/*those states are ok*/
		break;
267
	}
268

269
	if (lev->send_custom_headers){
270
		lev->op->setSentCustomHeaders(lev->send_custom_headers);
271
		sal_custom_header_free(lev->send_custom_headers);
272
		lev->send_custom_headers=NULL;
273
	}else lev->op->setSentCustomHeaders(NULL);
274

275
	body_handler = sal_body_handler_from_content(body);
276
	auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
Ghislain MARY's avatar
Ghislain MARY committed
277
	err=subscribeOp->subscribe(lev->name,lev->expires,body_handler);
278 279
	if (err==0){
		if (lev->subscription_state==LinphoneSubscriptionNone)
280
			linphone_event_set_state(lev,LinphoneSubscriptionOutgoingProgress);
281
	}
282 283 284
	return err;
}

285
LinphoneStatus linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
286
	return linphone_event_send_subscribe(lev,body);
287 288
}

289
LinphoneStatus linphone_event_refresh_subscribe(LinphoneEvent *lev) {
290
	return lev->op->refresh();
291 292
}

293
LinphoneStatus linphone_event_accept_subscription(LinphoneEvent *lev){
294
	int err;
295
	if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){
296 297 298
		ms_error("linphone_event_accept_subscription(): cannot accept subscription if subscription wasn't just received.");
		return -1;
	}
299 300
	auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
	err=subscribeOp->accept();
301 302 303 304 305 306
	if (err==0){
		linphone_event_set_state(lev,LinphoneSubscriptionActive);
	}
	return err;
}

307
LinphoneStatus linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){
308
	int err;
309
	if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){
310 311 312
		ms_error("linphone_event_deny_subscription(): cannot deny subscription if subscription wasn't just received.");
		return -1;
	}
313
	auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
314
	err=subscribeOp->decline(linphone_reason_to_sal(reason));
315 316
	linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
	return err;
317 318
}

319
LinphoneStatus linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){
320
	SalBodyHandler *body_handler;
321
	if (lev->subscription_state!=LinphoneSubscriptionActive && lev->subscription_state!=LinphoneSubscriptionIncomingReceived){
322 323 324 325 326 327 328
		ms_error("linphone_event_notify(): cannot notify if subscription is not active.");
		return -1;
	}
	if (lev->dir!=LinphoneSubscriptionIncoming){
		ms_error("linphone_event_notify(): cannot notify if not an incoming subscription.");
		return -1;
	}
329
	body_handler = sal_body_handler_from_content(body, false);
330
	auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
331
	return subscribeOp->notify(body_handler);
332 333
}

334 335 336
static LinphoneEvent *_linphone_core_create_publish(LinphoneCore *core, LinphoneProxyConfig *cfg, const LinphoneAddress *resource, const char *event, int expires){
	LinphoneCore *lc = core;
	LinphoneEvent *lev;
337

338 339 340 341 342 343 344 345 346 347
	if (!lc && cfg) {
		if (cfg->lc)
			lc = cfg->lc;
		else  {
			ms_error("Cannot create publish from proxy config [%p] not attached to any core",cfg);
			return NULL;
		}
	}
	if (!resource && cfg)
		resource = linphone_proxy_config_get_identity_address(cfg);
348

349 350
	lev = linphone_event_new_with_op(lc, new SalPublishOp(lc->sal), LinphoneSubscriptionInvalidDir, event);
	lev->expires = expires;
351
	linphone_configure_op_with_proxy(lc,lev->op,resource,NULL, !!lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0),cfg);
352
	lev->op->setManualRefresherMode(!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1));
353 354
	return lev;
}
355 356 357 358
LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
	return _linphone_core_create_publish(lc, NULL, resource, event, expires);
}
LinphoneEvent *linphone_proxy_config_create_publish(LinphoneProxyConfig *cfg, const char *event, int expires) {
359

360
	return _linphone_core_create_publish(NULL, cfg,NULL, event, expires);
361 362


363
}
364 365 366 367 368 369
LinphoneEvent *linphone_core_create_one_shot_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event){
	LinphoneEvent *lev = linphone_core_create_publish(lc, resource, event, -1);
	lev->oneshot = TRUE;
	return lev;
}

370
static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body, bool_t notify_err){
371
	SalBodyHandler *body_handler;
372
	int err;
373

374
	if (lev->dir!=LinphoneSubscriptionInvalidDir){
375 376 377
		ms_error("linphone_event_update_publish(): this is not a PUBLISH event.");
		return -1;
	}
378
	if (lev->send_custom_headers){
379
		lev->op->setSentCustomHeaders(lev->send_custom_headers);
380
		sal_custom_header_free(lev->send_custom_headers);
381
		lev->send_custom_headers=NULL;
382
	} else lev->op->setSentCustomHeaders(NULL);
383
	body_handler = sal_body_handler_from_content(body);
384
	auto publishOp = dynamic_cast<SalPublishOp *>(lev->op);
Ghislain MARY's avatar
Ghislain MARY committed
385
	err=publishOp->publish(lev->name,lev->expires,body_handler);
386 387
	if (err==0){
		linphone_event_set_publish_state(lev,LinphonePublishProgress);
388
	}else if (notify_err){
389 390 391
		linphone_event_set_publish_state(lev,LinphonePublishError);
	}
	return err;
392 393
}

394 395 396 397 398 399 400 401 402 403 404 405
LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
	int err;
	LinphoneEvent *lev=linphone_core_create_publish(lc,resource,event,expires);
	err=_linphone_event_send_publish(lev,body,FALSE);
	if (err==-1){
		linphone_event_unref(lev);
		lev=NULL;
	}
	return lev;
}


406
LinphoneStatus linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body){
407 408 409
	return _linphone_event_send_publish(lev,body,TRUE);
}

410
LinphoneStatus linphone_event_update_publish(LinphoneEvent* lev, const LinphoneContent* body ) {
411 412 413
	return linphone_event_send_publish(lev,body);
}

414
LinphoneStatus linphone_event_refresh_publish(LinphoneEvent *lev) {
415
	return lev->op->refresh();
416 417
}
void linphone_event_pause_publish(LinphoneEvent *lev) {
418
	if (lev->op) lev->op->stopRefreshing();
419 420 421
}
void linphone_event_unpublish(LinphoneEvent *lev) {
	lev->terminating = TRUE; /* needed to get clear event*/
422
	if (lev->op) {
423 424 425
		auto op = dynamic_cast<SalPublishOp *>(lev->op);
		op->unpublish();
	}
426
}
427
void linphone_event_set_user_data(LinphoneEvent *ev, void *up){
428 429 430
	ev->userdata=up;
}

431
void *linphone_event_get_user_data(const LinphoneEvent *ev){
432 433 434
	return ev->userdata;
}

435 436 437 438 439
void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const char *value){
	ev->send_custom_headers=sal_custom_header_append(ev->send_custom_headers, name, value);
}

const char* linphone_event_get_custom_header(LinphoneEvent* ev, const char* name){
440
	const SalCustomHeader *ch=ev->op->getRecvCustomHeaders();
441 442 443 444
	return sal_custom_header_find(ch,name);
}


445
void linphone_event_terminate(LinphoneEvent *lev){
446 447
	// if event was already terminated (including on error), we should not terminate it again
	// otherwise it will be unreffed twice.
448
	if (lev->publish_state == LinphonePublishError || lev->publish_state == LinphonePublishCleared) {
449 450 451 452 453 454
		return;
	}
	if (lev->subscription_state == LinphoneSubscriptionError || lev->subscription_state == LinphoneSubscriptionTerminated) {
		return;
	}

455
	lev->terminating=TRUE;
456
	if (lev->dir==LinphoneSubscriptionIncoming){
457
		auto op = dynamic_cast<SalSubscribeOp *>(lev->op);
458
		op->closeNotify();
459
	}else if (lev->dir==LinphoneSubscriptionOutgoing){
460
		auto op = dynamic_cast<SalSubscribeOp *>(lev->op);
461
		op->unsubscribe();
462
	}
463

464
	if (lev->publish_state!=LinphonePublishNone){
465
		if (lev->publish_state==LinphonePublishOk && lev->expires!=-1){
466
			auto op = dynamic_cast<SalPublishOp *>(lev->op);
467
			op->unpublish();
468
		}
469
		linphone_event_set_publish_state(lev,LinphonePublishCleared);
470 471
		return;
	}
472

473
	if (lev->subscription_state!=LinphoneSubscriptionNone){
474
		linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
475
		return;
476 477 478
	}
}

479 480

LinphoneEvent *linphone_event_ref(LinphoneEvent *lev){
481
	belle_sip_object_ref(lev);
482 483 484 485
	return lev;
}

static void linphone_event_destroy(LinphoneEvent *lev){
486
	if (lev->ei) linphone_error_info_unref(lev->ei);
487
	if (lev->op) lev->op->release();
Ghislain MARY's avatar
Ghislain MARY committed
488
	if (lev->send_custom_headers) sal_custom_header_free(lev->send_custom_headers);
Ronan's avatar
Ronan committed
489 490
	if (lev->to_address) linphone_address_unref(lev->to_address);
	if (lev->from_address) linphone_address_unref(lev->from_address);
491
	if (lev->remote_contact_address) linphone_address_unref(lev->remote_contact_address);
492
	linphone_event_cbs_unref(lev->callbacks);
Ronan's avatar
Ronan committed
493

494
	ms_free(lev->name);
495 496
}

497
void linphone_event_unref(LinphoneEvent *lev){
498
	belle_sip_object_unref(lev);
499 500
}

Simon Morlat's avatar
Simon Morlat committed
501
LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev){
502 503
	return lev->dir;
}
504 505

LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev){
506
	return lev->subscription_state;
507 508 509 510 511 512
}

const char *linphone_event_get_name(const LinphoneEvent *lev){
	return lev->name;
}

513 514 515
static const LinphoneAddress *_linphone_event_cache_to (const LinphoneEvent *lev) {
	if (lev->to_address)
		linphone_address_unref(lev->to_address);
516
	char *buf = sal_address_as_string(lev->op->getToAddress());
517 518 519 520 521 522 523 524
	((LinphoneEvent *)lev)->to_address = linphone_address_new(buf);
	ms_free(buf);
	return lev->to_address;
}

static const LinphoneAddress *_linphone_event_cache_from (const LinphoneEvent *lev) {
	if (lev->from_address)
		linphone_address_unref(lev->from_address);
525
	char *buf = sal_address_as_string(lev->op->getFromAddress());
526 527 528 529 530
	((LinphoneEvent *)lev)->from_address = linphone_address_new(buf);
	ms_free(buf);
	return lev->from_address;
}

531 532 533
static const LinphoneAddress *_linphone_event_cache_remote_contact (const LinphoneEvent *lev) {
	if (lev->remote_contact_address)
		linphone_address_unref(lev->remote_contact_address);
534
	char *buf = sal_address_as_string(lev->op->getRemoteContactAddress());
535 536 537 538 539
	((LinphoneEvent *)lev)->remote_contact_address = linphone_address_new(buf);
	ms_free(buf);
	return lev->remote_contact_address;
}

540 541 542 543
const LinphoneAddress *linphone_event_get_from (const LinphoneEvent *lev) {
	if (lev->is_out_of_dialog_op && lev->dir == LinphoneSubscriptionOutgoing)
		return _linphone_event_cache_to(lev);
	return _linphone_event_cache_from(lev);
544 545 546
}

const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){
547 548 549
	if (lev->is_out_of_dialog_op && lev->dir == LinphoneSubscriptionOutgoing)
		return _linphone_event_cache_from(lev);
	return _linphone_event_cache_to(lev);
550 551
}

552 553 554 555
const LinphoneAddress *linphone_event_get_remote_contact (const LinphoneEvent *lev) {
	return _linphone_event_cache_remote_contact(lev);
}

556 557 558 559
LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev){
	return lev->lc;
}

560 561 562
static belle_sip_error_code _linphone_event_marshall(belle_sip_object_t *obj, char* buff, size_t buff_size, size_t *offset) {
	LinphoneEvent *ev = (LinphoneEvent*)obj;
	belle_sip_error_code err = BELLE_SIP_OK;
563 564

	err = belle_sip_snprintf(buff, buff_size, offset, "%s of %s", ev->dir == LinphoneSubscriptionIncoming ?
565
		"Incoming Subscribe" : (ev->dir == LinphoneSubscriptionOutgoing ? "Outgoing subscribe" : "Publish"), ev->name);
566

567 568 569
	return err;
}

570 571 572 573 574 575 576 577 578 579
void _linphone_event_notify_notify_response(const LinphoneEvent *lev) {
	LinphoneEventCbsNotifyResponseCb cb = linphone_event_cbs_get_notify_response(lev->callbacks);
	if (cb)
		cb(lev);
}

LinphoneEventCbs *linphone_event_get_callbacks(const LinphoneEvent *ev) {
	return ev->callbacks;
}

580 581 582 583 584 585 586 587
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneEvent);

BELLE_SIP_INSTANCIATE_VPTR(LinphoneEvent, belle_sip_object_t,
	(belle_sip_object_destroy_t) linphone_event_destroy,
	NULL, // clone
	_linphone_event_marshall,
	FALSE
);