vtables.c 13.7 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
linphone
Copyright (C) 2000  Simon MORLAT (simon.morlat@linphone.org)
Copyright (C) 2010  Belledonne Communications SARL

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
18
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Simon Morlat's avatar
Simon Morlat committed
19 20 21 22 23 24 25 26 27 28 29 30 31
*/

#include "private.h"


LinphoneCoreVTable *linphone_core_v_table_new() {
	return ms_new0(LinphoneCoreVTable,1);
}

void linphone_core_v_table_set_user_data(LinphoneCoreVTable *table, void *data) {
	table->user_data = data;
}

32
void* linphone_core_v_table_get_user_data(const LinphoneCoreVTable *table) {
Simon Morlat's avatar
Simon Morlat committed
33 34 35 36 37 38 39 40
	return table->user_data;
}

void linphone_core_v_table_destroy(LinphoneCoreVTable* table) {
	ms_free(table);
}

LinphoneCoreVTable *linphone_core_get_current_vtable(LinphoneCore *lc) {
41 42
	if (lc->current_cbs != NULL) return lc->current_cbs->vtable;
	else return NULL;
Simon Morlat's avatar
Simon Morlat committed
43 44 45
}

static void cleanup_dead_vtable_refs(LinphoneCore *lc){
46
	bctbx_list_t *it,*next_it;
47

48
	if (lc->vtable_notify_recursion > 0) return; /*don't cleanup vtable if we are iterating through a listener list.*/
Simon Morlat's avatar
Simon Morlat committed
49 50 51
	for(it=lc->vtable_refs; it!=NULL; ){
		VTableReference *ref=(VTableReference*)it->data;
		next_it=it->next;
Simon Morlat's avatar
Simon Morlat committed
52
		if (ref->valid == 0){
53
			lc->vtable_refs=bctbx_list_erase_link(lc->vtable_refs, it);
Simon Morlat's avatar
Simon Morlat committed
54
			belle_sip_object_unref(ref->cbs);
Simon Morlat's avatar
Simon Morlat committed
55 56 57 58 59 60
			ms_free(ref);
		}
		it=next_it;
	}
}

61
#define NOTIFY_IF_EXIST(function_name, ...) \
62
	bctbx_list_t* iterator; \
Simon Morlat's avatar
Simon Morlat committed
63
	VTableReference *ref; \
64
	bool_t has_cb = FALSE; \
65 66
	lc->vtable_notify_recursion++;\
	for (iterator=lc->vtable_refs; iterator!=NULL; iterator=iterator->next){\
67 68
		if ((ref=(VTableReference*)iterator->data)->valid && (lc->current_cbs=ref->cbs)->vtable->function_name) {\
			lc->current_cbs->vtable->function_name(__VA_ARGS__);\
69 70
			has_cb = TRUE;\
		}\
71 72 73
	}\
	lc->vtable_notify_recursion--;\
	if (has_cb) ms_message("Linphone core [%p] notified [%s]",lc,#function_name)
Simon Morlat's avatar
Simon Morlat committed
74

75
#define NOTIFY_IF_EXIST_INTERNAL(function_name, internal_val, ...) \
76
	bctbx_list_t* iterator; \
77
	VTableReference *ref; \
78 79
	lc->vtable_notify_recursion++;\
	for (iterator=lc->vtable_refs; iterator!=NULL; iterator=iterator->next){\
80 81
		if ((ref=(VTableReference*)iterator->data)->valid && (lc->current_cbs=ref->cbs)->vtable->function_name && (ref->internal == internal_val)) {\
			lc->current_cbs->vtable->function_name(__VA_ARGS__);\
82
		}\
83 84
	}\
	lc->vtable_notify_recursion--;
85

Simon Morlat's avatar
Simon Morlat committed
86
void linphone_core_notify_global_state_changed(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message) {
87
	NOTIFY_IF_EXIST(global_state_changed,lc,gstate,message);
Simon Morlat's avatar
Simon Morlat committed
88 89 90 91
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message){
92
	NOTIFY_IF_EXIST(call_state_changed, lc,call,cstate,message);
Simon Morlat's avatar
Simon Morlat committed
93 94 95 96
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t on, const char *authentication_token) {
97
	NOTIFY_IF_EXIST(call_encryption_changed, lc,call,on,authentication_token);
Simon Morlat's avatar
Simon Morlat committed
98 99 100 101
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){
102
	NOTIFY_IF_EXIST(registration_state_changed, lc,cfg,cstate,message);
Simon Morlat's avatar
Simon Morlat committed
103 104
	cleanup_dead_vtable_refs(lc);
}
105
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
106
#pragma GCC diagnostic push
107
#endif
108 109 110
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
111
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
112
#endif
Simon Morlat's avatar
Simon Morlat committed
113
void linphone_core_notify_show_interface(LinphoneCore *lc){
114
	NOTIFY_IF_EXIST(show, lc);
Simon Morlat's avatar
Simon Morlat committed
115 116 117 118
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_display_status(LinphoneCore *lc, const char *message) {
119
	NOTIFY_IF_EXIST(display_status, lc,message);
Simon Morlat's avatar
Simon Morlat committed
120 121 122 123
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_display_message(LinphoneCore *lc, const char *message){
124
	NOTIFY_IF_EXIST(display_message, lc,message);
Simon Morlat's avatar
Simon Morlat committed
125 126 127 128
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_display_warning(LinphoneCore *lc, const char *message){
129
	NOTIFY_IF_EXIST(display_warning, lc,message);
Simon Morlat's avatar
Simon Morlat committed
130 131 132 133
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_display_url(LinphoneCore *lc, const char *message, const char *url){
134
	NOTIFY_IF_EXIST(display_url, lc,message,url);
Simon Morlat's avatar
Simon Morlat committed
135 136
	cleanup_dead_vtable_refs(lc);
}
137
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
138
#pragma GCC diagnostic pop
139
#endif
140 141
void linphone_core_notify_notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) {
	NOTIFY_IF_EXIST(notify_presence_received, lc, lf);
Simon Morlat's avatar
Simon Morlat committed
142 143 144
	cleanup_dead_vtable_refs(lc);
}

145 146
void linphone_core_notify_notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *lf, const char *uri_or_tel, const LinphonePresenceModel *presence_model) {
	NOTIFY_IF_EXIST(notify_presence_received_for_uri_or_tel, lc, lf, uri_or_tel, presence_model);
Simon Morlat's avatar
Simon Morlat committed
147 148 149
	cleanup_dead_vtable_refs(lc);
}

150 151
void linphone_core_notify_new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url) {
	NOTIFY_IF_EXIST(new_subscription_requested, lc, lf, url);
Simon Morlat's avatar
Simon Morlat committed
152 153 154
	cleanup_dead_vtable_refs(lc);
}

155 156 157

void linphone_core_notify_authentication_requested(LinphoneCore *lc, LinphoneAuthInfo *ai, LinphoneAuthMethod method) {
	NOTIFY_IF_EXIST(authentication_requested, lc, ai, method);
158 159 160 161 162
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_call_log_updated(LinphoneCore *lc, LinphoneCallLog *newcl) {
	NOTIFY_IF_EXIST(call_log_updated, lc, newcl);
Simon Morlat's avatar
Simon Morlat committed
163 164
	cleanup_dead_vtable_refs(lc);
}
165
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
166
#pragma GCC diagnostic push
167
#endif
168 169 170
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
171
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
172
#endif
Simon Morlat's avatar
Simon Morlat committed
173

174 175 176 177 178
void linphone_core_notify_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
	NOTIFY_IF_EXIST(auth_info_requested, lc, realm, username, domain);
	cleanup_dead_vtable_refs(lc);
}

Simon Morlat's avatar
Simon Morlat committed
179
void linphone_core_notify_text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message){
180
	NOTIFY_IF_EXIST(text_received, lc,room,from,message);
Simon Morlat's avatar
Simon Morlat committed
181 182
	cleanup_dead_vtable_refs(lc);
}
183
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
184
#pragma GCC diagnostic pop
185
#endif
Simon Morlat's avatar
Simon Morlat committed
186 187

void linphone_core_notify_message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message){
188
	NOTIFY_IF_EXIST(message_received, lc,room,message);
Simon Morlat's avatar
Simon Morlat committed
189 190
	cleanup_dead_vtable_refs(lc);
}
191 192 193 194 195

void linphone_core_notify_message_received_unable_decrypt(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message){
	NOTIFY_IF_EXIST(message_received_unable_decrypt, lc,room,message);
	cleanup_dead_vtable_refs(lc);
}
196
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
197
#pragma GCC diagnostic push
198
#endif
199 200 201
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
202
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
203
#endif
Simon Morlat's avatar
Simon Morlat committed
204
void linphone_core_notify_file_transfer_recv(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size) {
205
	NOTIFY_IF_EXIST(file_transfer_recv, lc,message,content,buff,size);
Simon Morlat's avatar
Simon Morlat committed
206 207 208 209
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message,  const LinphoneContent* content, char* buff, size_t* size) {
210
	NOTIFY_IF_EXIST(file_transfer_send, lc,message,content,buff,size);
Simon Morlat's avatar
Simon Morlat committed
211 212 213 214
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) {
215
	NOTIFY_IF_EXIST(file_transfer_progress_indication, lc,message,content,offset,total);
Simon Morlat's avatar
Simon Morlat committed
216 217
	cleanup_dead_vtable_refs(lc);
}
218
#if __clang__ || ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4)
219
#pragma GCC diagnostic pop
220
#endif
Simon Morlat's avatar
Simon Morlat committed
221
void linphone_core_notify_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) {
222 223 224 225 226
	LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(lc);
	if (linphone_im_notif_policy_get_recv_is_composing(policy) == TRUE) {
		NOTIFY_IF_EXIST(is_composing_received, lc,room);
		cleanup_dead_vtable_refs(lc);
	}
Simon Morlat's avatar
Simon Morlat committed
227 228 229
}

void linphone_core_notify_dtmf_received(LinphoneCore* lc, LinphoneCall *call, int dtmf) {
230
	NOTIFY_IF_EXIST(dtmf_received, lc,call,dtmf);
Simon Morlat's avatar
Simon Morlat committed
231 232 233 234
	cleanup_dead_vtable_refs(lc);
}

bool_t linphone_core_dtmf_received_has_listener(const LinphoneCore* lc) {
235
	bctbx_list_t* iterator;
Simon Morlat's avatar
Simon Morlat committed
236 237
	for (iterator=lc->vtable_refs; iterator!=NULL; iterator=iterator->next){
		VTableReference *ref=(VTableReference*)iterator->data;
238
		if (ref->valid && ref->cbs->vtable->dtmf_received)
Simon Morlat's avatar
Simon Morlat committed
239 240 241 242 243 244
			return TRUE;
	}
	return FALSE;
}

void linphone_core_notify_refer_received(LinphoneCore *lc, const char *refer_to) {
245
	NOTIFY_IF_EXIST(refer_received, lc,refer_to);
Simon Morlat's avatar
Simon Morlat committed
246 247 248 249
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf) {
250
	NOTIFY_IF_EXIST(buddy_info_updated, lc,lf);
Simon Morlat's avatar
Simon Morlat committed
251 252 253 254
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) {
255
	NOTIFY_IF_EXIST(transfer_state_changed, lc,transfered,new_call_state);
Simon Morlat's avatar
Simon Morlat committed
256 257 258 259
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats) {
260
	NOTIFY_IF_EXIST(call_stats_updated, lc,call,stats);
Simon Morlat's avatar
Simon Morlat committed
261 262 263 264
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_info_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg) {
265
	NOTIFY_IF_EXIST(info_received, lc,call,msg);
Simon Morlat's avatar
Simon Morlat committed
266 267 268 269
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) {
270
	NOTIFY_IF_EXIST(configuring_status, lc,status,message);
Simon Morlat's avatar
Simon Morlat committed
271 272 273 274
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_network_reachable(LinphoneCore *lc, bool_t reachable) {
275
	NOTIFY_IF_EXIST(network_reachable, lc,reachable);
Simon Morlat's avatar
Simon Morlat committed
276 277 278 279
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body) {
280
	NOTIFY_IF_EXIST_INTERNAL(notify_received, linphone_event_is_internal(lev), lc, lev, notified_event, body);
Simon Morlat's avatar
Simon Morlat committed
281 282 283 284
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) {
285
	NOTIFY_IF_EXIST_INTERNAL(subscription_state_changed,linphone_event_is_internal(lev), lc,lev,state);
Simon Morlat's avatar
Simon Morlat committed
286 287 288 289
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state) {
290
	NOTIFY_IF_EXIST_INTERNAL(publish_state_changed, linphone_event_is_internal(lev), lc, lev, state);
Simon Morlat's avatar
Simon Morlat committed
291 292 293 294
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_log_collection_upload_state_changed(LinphoneCore *lc, LinphoneCoreLogCollectionUploadState state, const char *info) {
295
	NOTIFY_IF_EXIST(log_collection_upload_state_changed, lc, state, info);
Simon Morlat's avatar
Simon Morlat committed
296 297 298 299
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_log_collection_upload_progress_indication(LinphoneCore *lc, size_t offset, size_t total) {
300
	NOTIFY_IF_EXIST(log_collection_upload_progress_indication, lc, offset, total);
Simon Morlat's avatar
Simon Morlat committed
301 302 303
	cleanup_dead_vtable_refs(lc);
}

304 305 306 307 308 309 310 311 312 313
void linphone_core_notify_friend_list_created(LinphoneCore *lc, LinphoneFriendList *list) {
	NOTIFY_IF_EXIST(friend_list_created, lc, list);
	cleanup_dead_vtable_refs(lc);
}

void linphone_core_notify_friend_list_removed(LinphoneCore *lc, LinphoneFriendList *list) {
	NOTIFY_IF_EXIST(friend_list_removed, lc, list);
	cleanup_dead_vtable_refs(lc);
}

314 315 316 317 318
void linphone_core_notify_call_created(LinphoneCore *lc, LinphoneCall *call) {
	NOTIFY_IF_EXIST(call_created, lc, call);
	cleanup_dead_vtable_refs(lc);
}

319
static VTableReference * v_table_reference_new(LinphoneCoreCbs *cbs, bool_t internal){
Simon Morlat's avatar
Simon Morlat committed
320
	VTableReference *ref=ms_new0(VTableReference,1);
321
	ref->valid=TRUE;
322
	ref->internal = internal;
Ghislain MARY's avatar
Ghislain MARY committed
323
	ref->cbs=linphone_core_cbs_ref(cbs);
Simon Morlat's avatar
Simon Morlat committed
324 325 326 327
	return ref;
}

void v_table_reference_destroy(VTableReference *ref){
Ghislain MARY's avatar
Ghislain MARY committed
328
	linphone_core_cbs_unref(ref->cbs);
Simon Morlat's avatar
Simon Morlat committed
329 330 331
	ms_free(ref);
}

332 333 334
void _linphone_core_add_callbacks(LinphoneCore *lc, LinphoneCoreCbs *vtable, bool_t internal) {
	ms_message("Core callbacks [%p] registered on core [%p]", vtable, lc);
	lc->vtable_refs=bctbx_list_append(lc->vtable_refs,v_table_reference_new(vtable, internal));
Simon Morlat's avatar
Simon Morlat committed
335 336 337
}

void linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable){
338 339 340
	LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
	_linphone_core_cbs_set_v_table(cbs, vtable, FALSE);
	_linphone_core_add_callbacks(lc, cbs, FALSE);
Ghislain MARY's avatar
Ghislain MARY committed
341
	linphone_core_cbs_unref(cbs);
342 343 344 345
}

void linphone_core_add_callbacks(LinphoneCore *lc, LinphoneCoreCbs *cbs) {
	_linphone_core_add_callbacks(lc, cbs, FALSE);
Simon Morlat's avatar
Simon Morlat committed
346 347 348
}

void linphone_core_remove_listener(LinphoneCore *lc, const LinphoneCoreVTable *vtable) {
349
	bctbx_list_t *it;
350
	ms_message("Vtable [%p] unregistered on core [%p]",vtable,lc);
Simon Morlat's avatar
Simon Morlat committed
351 352
	for(it=lc->vtable_refs; it!=NULL; it=it->next){
		VTableReference *ref=(VTableReference*)it->data;
353 354 355 356 357 358 359 360 361 362 363 364 365 366
		if (ref->cbs->vtable==vtable) {
			ref->valid=FALSE;
		}
	}
}

void linphone_core_remove_callbacks(LinphoneCore *lc, const LinphoneCoreCbs *cbs) {
	bctbx_list_t *it;
	ms_message("Callbacks [%p] unregistered on core [%p]",cbs,lc);
	for(it=lc->vtable_refs; it!=NULL; it=it->next){
		VTableReference *ref=(VTableReference*)it->data;
		if (ref->cbs==cbs) {
			ref->valid=FALSE;
		}
Simon Morlat's avatar
Simon Morlat committed
367 368
	}
}