c-chat-room.cpp 23.7 KB
Newer Older
1 2
/*
 * c-chat-room.cpp
Ronan's avatar
Ronan committed
3
 * Copyright (C) 2010-2018 Belledonne Communications SARL
4
 *
Ghislain MARY's avatar
Ghislain MARY committed
5 6 7 8
 * 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.
9 10 11 12 13 14 15
 *
 * 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
Ghislain MARY's avatar
Ghislain MARY committed
16 17
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 19
 */

20 21
#include <algorithm>

22
// TODO: Remove me later.
23
#include "linphone/chat.h"
Ronan's avatar
Ronan committed
24

25
#include "linphone/api/c-chat-room.h"
26
#include "linphone/wrapper_utils.h"
27

28
#include "address/identity-address.h"
29
#include "c-wrapper/c-wrapper.h"
Ghislain MARY's avatar
Ghislain MARY committed
30
#include "call/call.h"
31
#include "chat/chat-message/chat-message-p.h"
Ronan's avatar
Ronan committed
32
#include "chat/chat-room/basic-chat-room.h"
33 34
#include "chat/chat-room/client-group-chat-room-p.h"
#include "chat/chat-room/client-group-to-basic-chat-room.h"
Ronan's avatar
Ronan committed
35
#include "chat/chat-room/real-time-text-chat-room-p.h"
36
#include "chat/chat-room/server-group-chat-room-p.h"
37
#include "conference/participant.h"
38
#include "core/core-p.h"
39
#include "event-log/event-log.h"
40

Ronan's avatar
Ronan committed
41
// =============================================================================
42

Ronan's avatar
Ronan committed
43
using namespace std;
44

Ronan's avatar
Ronan committed
45 46
static void _linphone_chat_room_constructor (LinphoneChatRoom *cr);
static void _linphone_chat_room_destructor (LinphoneChatRoom *cr);
47

48
L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(
49
	ChatRoom,
50
	_linphone_chat_room_constructor, _linphone_chat_room_destructor,
51
	LinphoneChatRoomCbs *cbs;
52 53
	bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */
	LinphoneChatRoomCbs *currentCbs; /* The current LinphoneCallCbs object used to call a callback */
54
	mutable LinphoneAddress *conferenceAddressCache;
55 56
	mutable LinphoneAddress *peerAddressCache;
	mutable LinphoneAddress *localAddressCache;
57
	mutable bctbx_list_t *composingAddresses;
58 59
)

Ronan's avatar
Ronan committed
60
static void _linphone_chat_room_constructor (LinphoneChatRoom *cr) {
61 62
	cr->cbs = linphone_chat_room_cbs_new();
}
63

Ronan's avatar
Ronan committed
64
static void _linphone_chat_room_destructor (LinphoneChatRoom *cr) {
65
	linphone_chat_room_cbs_unref(cr->cbs);
66
	if (cr->conferenceAddressCache)
67
		linphone_address_unref(cr->conferenceAddressCache);
68
	if (cr->peerAddressCache)
69
		linphone_address_unref(cr->peerAddressCache);
70 71
	if (cr->localAddressCache)
		linphone_address_unref(cr->localAddressCache);
72 73
	if (cr->composingAddresses)
		bctbx_list_free_with_data(cr->composingAddresses, (bctbx_list_free_func)linphone_address_unref);
74
	bctbx_list_free_with_data(cr->callbacks, (bctbx_list_free_func)linphone_chat_room_cbs_unref);
75 76
}

77 78 79 80 81 82 83
static list<LinphonePrivate::IdentityAddress> _get_identity_address_list_from_address_list(list<LinphonePrivate::Address> addressList) {
	list<LinphonePrivate::IdentityAddress> lIdent;
	for (const auto &addr : addressList)
		lIdent.push_back(LinphonePrivate::IdentityAddress(addr));
	return lIdent;
}

Ronan's avatar
Ronan committed
84 85 86
// =============================================================================
// Public functions.
// =============================================================================
87

Ronan's avatar
Ronan committed
88
void linphone_chat_room_send_message (LinphoneChatRoom *cr, const char *msg) {
89
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createChatMessage(msg)->send();
90 91
}

Ronan's avatar
Ronan committed
92
bool_t linphone_chat_room_is_remote_composing (const LinphoneChatRoom *cr) {
93
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->isRemoteComposing();
94 95
}

Ronan's avatar
Ronan committed
96
LinphoneCore *linphone_chat_room_get_lc (const LinphoneChatRoom *cr) {
97 98 99
	return linphone_chat_room_get_core(cr);
}

Ronan's avatar
Ronan committed
100
LinphoneCore *linphone_chat_room_get_core (const LinphoneChatRoom *cr) {
101
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCore()->getCCore();
102 103
}

Ronan's avatar
Ronan committed
104
const LinphoneAddress *linphone_chat_room_get_peer_address (LinphoneChatRoom *cr) {
105 106 107
	if (cr->peerAddressCache) {
		linphone_address_unref(cr->peerAddressCache);
	}
108

109
	cr->peerAddressCache = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getPeerAddress().asString().c_str());
110 111 112
	return cr->peerAddressCache;
}

113 114 115 116 117 118 119 120 121
const LinphoneAddress *linphone_chat_room_get_local_address (LinphoneChatRoom *cr) {
	if (cr->localAddressCache) {
		linphone_address_unref(cr->localAddressCache);
	}

	cr->localAddressCache = linphone_address_new(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLocalAddress().asString().c_str());
	return cr->localAddressCache;
}

Ronan's avatar
Ronan committed
122
LinphoneChatMessage *linphone_chat_room_create_message (LinphoneChatRoom *cr, const char *message) {
123
	shared_ptr<LinphonePrivate::ChatMessage> cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createChatMessage(L_C_TO_STRING(message));
124 125 126
	LinphoneChatMessage *object = L_INIT(ChatMessage);
	L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr);
	return object;
127 128
}

Ronan's avatar
Ronan committed
129 130 131 132 133 134 135 136 137
LinphoneChatMessage *linphone_chat_room_create_message_2 (
	LinphoneChatRoom *cr,
	const char *message,
	const char *external_body_url,
	LinphoneChatMessageState state,
	time_t time,
	bool_t is_read,
	bool_t is_incoming
) {
138
	LinphoneChatMessage *msg = linphone_chat_room_create_message(cr, message);
139

140
	linphone_chat_message_set_external_body_url(msg, external_body_url ? ms_strdup(external_body_url) : NULL);
141 142 143 144 145

	LinphonePrivate::ChatMessagePrivate *dMsg = L_GET_PRIVATE_FROM_C_OBJECT(msg);
	dMsg->setTime(time);
	dMsg->setState(static_cast<LinphonePrivate::ChatMessage::State>(state));

146 147 148
	return msg;
}

Ronan's avatar
Ronan committed
149
void linphone_chat_room_send_chat_message_2 (LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
150
	linphone_chat_message_ref(msg);
151
	L_GET_CPP_PTR_FROM_C_OBJECT(msg)->send();
152 153
}

Ronan's avatar
Ronan committed
154
void linphone_chat_room_send_chat_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
155
	L_GET_CPP_PTR_FROM_C_OBJECT(msg)->send();
156 157
}

158 159 160 161
void linphone_chat_room_receive_chat_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
	L_GET_PRIVATE_FROM_C_OBJECT(msg)->receive();
}

Ronan's avatar
Ronan committed
162
uint32_t linphone_chat_room_get_char (const LinphoneChatRoom *cr) {
Ghislain MARY's avatar
Ghislain MARY committed
163 164 165
	if (!(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities() & LinphonePrivate::ChatRoom::Capabilities::RealTimeText))
		return 0;
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->getChar();
166 167
}

Ronan's avatar
Ronan committed
168
void linphone_chat_room_compose (LinphoneChatRoom *cr) {
169
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->compose();
170 171
}

Ronan's avatar
Ronan committed
172
LinphoneCall *linphone_chat_room_get_call (const LinphoneChatRoom *cr) {
Ghislain MARY's avatar
Ghislain MARY committed
173 174 175
	if (!(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities() & LinphonePrivate::ChatRoom::Capabilities::RealTimeText))
		return nullptr;
	return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->getCall());
176 177
}

Ronan's avatar
Ronan committed
178
void linphone_chat_room_set_call (LinphoneChatRoom *cr, LinphoneCall *call) {
Ghislain MARY's avatar
Ghislain MARY committed
179 180 181
	if (!(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities() & LinphonePrivate::ChatRoom::Capabilities::RealTimeText))
		return;
	L_GET_PRIVATE_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->call = L_GET_CPP_PTR_FROM_C_OBJECT(call);
182 183
}

Ronan's avatar
Ronan committed
184
void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) {
185
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->markAsRead();
186 187
}

Ronan's avatar
Ronan committed
188
int linphone_chat_room_get_unread_messages_count (LinphoneChatRoom *cr) {
189
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getUnreadChatMessageCount();
190 191
}

Ronan's avatar
Ronan committed
192
int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) {
193
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatMessageCount();
194 195
}

Ronan's avatar
Ronan committed
196
void linphone_chat_room_delete_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
197 198 199 200 201
	shared_ptr<LinphonePrivate::EventLog> event = LinphonePrivate::MainDb::getEventFromKey(
		L_GET_PRIVATE_FROM_C_OBJECT(msg)->dbKey
	);
	if (event)
		LinphonePrivate::EventLog::deleteFromDatabase(event);
202 203
}

Ronan's avatar
Ronan committed
204
void linphone_chat_room_delete_history (LinphoneChatRoom *cr) {
205
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->deleteHistory();
206 207
}

Ronan's avatar
Ronan committed
208
bctbx_list_t *linphone_chat_room_get_history_range (LinphoneChatRoom *cr, int startm, int endm) {
209
	list<shared_ptr<LinphonePrivate::ChatMessage>> chatMessages;
210 211
	for (auto &event : L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getMessageHistoryRange(startm, endm))
		chatMessages.push_back(static_pointer_cast<LinphonePrivate::ConferenceChatMessageEvent>(event)->getChatMessage());
212 213

	return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(chatMessages);
214 215
}

Ronan's avatar
Ronan committed
216
bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_message) {
217
	return linphone_chat_room_get_history_range(cr, 0, nb_message);
218 219
}

220 221 222 223 224 225 226 227
bctbx_list_t *linphone_chat_room_get_history_range_message_events (LinphoneChatRoom *cr, int startm, int endm) {
	return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getMessageHistoryRange(startm, endm));
}

bctbx_list_t *linphone_chat_room_get_history_message_events (LinphoneChatRoom *cr, int nb_events) {
	return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getMessageHistory(nb_events));
}

228
bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int nb_events) {
229
	return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistory(nb_events));
230 231 232
}

bctbx_list_t *linphone_chat_room_get_history_range_events (LinphoneChatRoom *cr, int begin, int end) {
233
	return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistoryRange(begin, end));
234 235
}

236 237 238 239
int linphone_chat_room_get_history_events_size(LinphoneChatRoom *cr) {
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistorySize();
}

240
LinphoneChatMessage *linphone_chat_room_get_last_message_in_history(LinphoneChatRoom *cr) {
Ronan's avatar
Ronan committed
241
	shared_ptr<LinphonePrivate::ChatMessage> cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastChatMessageInHistory();
Benjamin REIS's avatar
Benjamin REIS committed
242 243 244
	if (!cppPtr)
		return nullptr;

Benjamin REIS's avatar
Benjamin REIS committed
245 246 247
	LinphoneChatMessage *object = L_INIT(ChatMessage);
	L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr);
	return object;
248 249
}

Ronan's avatar
Ronan committed
250
LinphoneChatMessage *linphone_chat_room_find_message (LinphoneChatRoom *cr, const char *message_id) {
251
	return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findChatMessage(message_id));
252 253
}

254
LinphoneChatRoomState linphone_chat_room_get_state (const LinphoneChatRoom *cr) {
255
	return (LinphoneChatRoomState)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getState();
256 257
}

258 259
bool_t linphone_chat_room_has_been_left (const LinphoneChatRoom *cr) {
	return (bool_t)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->hasBeenLeft();
260 261
}

262 263 264 265
time_t linphone_chat_room_get_last_update_time(const LinphoneChatRoom *cr) {
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastUpdateTime();
}

266
void linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) {
267 268 269
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant(
		LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)), nullptr, false
	);
270 271 272
}

void linphone_chat_room_add_participants (LinphoneChatRoom *cr, const bctbx_list_t *addresses) {
273 274 275 276 277
	list<LinphonePrivate::Address> lAddr = L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(addresses, Address);
	list<LinphonePrivate::IdentityAddress> lIdentAddr;
	for (const auto &addr : lAddr)
		lIdentAddr.push_back(LinphonePrivate::IdentityAddress(addr));
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipants(lIdentAddr, nullptr, false);
278 279 280
}

bool_t linphone_chat_room_can_handle_participants (const LinphoneChatRoom *cr) {
281
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->canHandleParticipants();
282 283
}

284
LinphoneParticipant *linphone_chat_room_find_participant (const LinphoneChatRoom *cr, const LinphoneAddress *addr) {
285 286 287
	return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(
		LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr))
	));
288 289
}

290 291
LinphoneChatRoomCapabilitiesMask linphone_chat_room_get_capabilities (const LinphoneChatRoom *cr) {
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities();
292 293
}

294
bool_t linphone_chat_room_has_capability(const LinphoneChatRoom *cr, int mask) {
295 296 297 298
	if (L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities() & mask) return true;
	return false;
}

299
const LinphoneAddress *linphone_chat_room_get_conference_address (const LinphoneChatRoom *cr) {
300
	if (cr->conferenceAddressCache)
301
		linphone_address_unref(cr->conferenceAddressCache);
302

303
	const LinphonePrivate::IdentityAddress &address = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getConferenceAddress();
304 305
	if (address.isValid())
		cr->conferenceAddressCache = linphone_address_new(address.asString().c_str());
306 307 308
	else
		cr->conferenceAddressCache = nullptr;
	return cr->conferenceAddressCache;
309 310
}

311 312 313 314
LinphoneParticipant *linphone_chat_room_get_me (const LinphoneChatRoom *cr) {
	return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getMe());
}

315
int linphone_chat_room_get_nb_participants (const LinphoneChatRoom *cr) {
316
	return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getParticipantCount();
317 318
}

Ronan's avatar
Ronan committed
319
bctbx_list_t *linphone_chat_room_get_participants (const LinphoneChatRoom *cr) {
320
	return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getParticipants());
321 322
}

323 324 325 326
const char * linphone_chat_room_get_subject (const LinphoneChatRoom *cr) {
	return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getSubject());
}

Ghislain MARY's avatar
Ghislain MARY committed
327 328 329 330
void linphone_chat_room_leave (LinphoneChatRoom *cr) {
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave();
}

331
void linphone_chat_room_remove_participant (LinphoneChatRoom *cr, LinphoneParticipant *participant) {
332
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipant(L_GET_CPP_PTR_FROM_C_OBJECT(participant));
333 334 335
}

void linphone_chat_room_remove_participants (LinphoneChatRoom *cr, const bctbx_list_t *participants) {
336
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->removeParticipants(L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(participants, Participant));
337 338
}

339 340 341 342 343
void linphone_chat_room_set_participant_admin_status (LinphoneChatRoom *cr, LinphoneParticipant *participant, bool_t isAdmin) {
	shared_ptr<LinphonePrivate::Participant> p = L_GET_CPP_PTR_FROM_C_OBJECT(participant);
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setParticipantAdminStatus(p, !!isAdmin);
}

344 345 346 347
void linphone_chat_room_set_subject (LinphoneChatRoom *cr, const char *subject) {
	L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setSubject(L_C_TO_STRING(subject));
}

348
const bctbx_list_t *linphone_chat_room_get_composing_addresses (LinphoneChatRoom *cr) {
349 350 351 352 353 354 355 356 357 358 359 360 361 362
	bctbx_list_free_with_data(cr->composingAddresses, (bctbx_list_free_func)linphone_address_unref);
	list<LinphonePrivate::Address> composingAddresses;
	// TODO: Improve perf or algorithm?
	{
		list<LinphonePrivate::IdentityAddress> addresses = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getComposingAddresses();
		transform(
			addresses.cbegin(), addresses.cend(),
			back_inserter(composingAddresses), [](const LinphonePrivate::Address &address) {
				return LinphonePrivate::IdentityAddress(address);
			}
		);
	}
	cr->composingAddresses = L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(composingAddresses);
	return cr->composingAddresses;
363 364
}

365
LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, const LinphoneContent *initial_content) {
Benjamin REIS's avatar
Benjamin REIS committed
366 367 368 369
	shared_ptr<LinphonePrivate::ChatMessage> cppPtr = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->createFileTransferMessage(initial_content);
	LinphoneChatMessage *object = L_INIT(ChatMessage);
	L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr);
	return object;
370 371
}

372 373 374 375 376 377 378 379
void linphone_chat_room_set_conference_address (LinphoneChatRoom *cr, const LinphoneAddress *confAddr) {
	char *addrStr = linphone_address_as_string(confAddr);
	LinphonePrivate::ServerGroupChatRoomPrivate *sgcr = dynamic_cast<LinphonePrivate::ServerGroupChatRoomPrivate *>(L_GET_PRIVATE_FROM_C_OBJECT(cr));
	if (sgcr)
		sgcr->setConferenceAddress(LinphonePrivate::IdentityAddress(addrStr));
	bctbx_free(addrStr);
}

380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
void linphone_chat_room_set_participant_devices (LinphoneChatRoom *cr, const LinphoneAddress *partAddr, const bctbx_list_t *partDevices) {
	char *addrStr = linphone_address_as_string(partAddr);
	list<LinphonePrivate::Address> lDevices = L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(partDevices, Address);
	list<LinphonePrivate::IdentityAddress> lIdentAddr;
	for (const auto &addr : lDevices)
		lIdentAddr.push_back(LinphonePrivate::IdentityAddress(addr));
	LinphonePrivate::ServerGroupChatRoomPrivate *sgcr = dynamic_cast<LinphonePrivate::ServerGroupChatRoomPrivate *>(L_GET_PRIVATE_FROM_C_OBJECT(cr));
	if (sgcr)
		sgcr->setParticipantDevices(LinphonePrivate::IdentityAddress(addrStr), lIdentAddr);
	bctbx_free(addrStr);
}

void linphone_chat_room_add_compatible_participants (LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsCompatible) {
	list<LinphonePrivate::Address> lPartsComp = L_GET_RESOLVED_CPP_LIST_FROM_C_LIST(participantsCompatible, Address);
	LinphonePrivate::ServerGroupChatRoomPrivate *sgcr = dynamic_cast<LinphonePrivate::ServerGroupChatRoomPrivate *>(L_GET_PRIVATE_FROM_C_OBJECT(cr));
	if (sgcr) {
		char *deviceAddrStr = linphone_address_as_string_uri_only(deviceAddr);
		sgcr->addCompatibleParticipants(LinphonePrivate::IdentityAddress(deviceAddrStr),
										_get_identity_address_list_from_address_list(lPartsComp)
		);
		bctbx_free(deviceAddrStr);
	}
}

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
// =============================================================================
// Callbacks
// =============================================================================

LinphoneChatRoomCbs *linphone_chat_room_get_callbacks (const LinphoneChatRoom *cr) {
	return cr->cbs;
}

void linphone_chat_room_add_callbacks (LinphoneChatRoom *cr, LinphoneChatRoomCbs *cbs) {
	cr->callbacks = bctbx_list_append(cr->callbacks, linphone_chat_room_cbs_ref(cbs));
}

void linphone_chat_room_remove_callbacks (LinphoneChatRoom *cr, LinphoneChatRoomCbs *cbs) {
	cr->callbacks = bctbx_list_remove(cr->callbacks, cbs);
	linphone_chat_room_cbs_unref(cbs);
}

LinphoneChatRoomCbs *linphone_chat_room_get_current_callbacks (const LinphoneChatRoom *cr) {
	return cr->currentCbs;
}

const bctbx_list_t *linphone_chat_room_get_callbacks_list(const LinphoneChatRoom *cr) {
	return cr->callbacks;
}

#define NOTIFY_IF_EXIST(cbName, functionName, ...) \
	LinphoneChatRoomCbs ## cbName ## Cb cb = linphone_chat_room_cbs_get_ ## functionName (cr->cbs); \
	if (cb) \
		cb(__VA_ARGS__); \
433 434
	bctbx_list_t *callbacks_copy = bctbx_list_copy(cr->callbacks); \
	for (bctbx_list_t *it = callbacks_copy; it; it = bctbx_list_next(it)) { \
435 436 437 438
		cr->currentCbs = reinterpret_cast<LinphoneChatRoomCbs *>(bctbx_list_get_data(it)); \
		cb = linphone_chat_room_cbs_get_ ## functionName (cr->currentCbs); \
		if (cb) \
			cb(__VA_ARGS__); \
439 440
	} \
	bctbx_free(callbacks_copy);
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505

void linphone_chat_room_notify_is_composing_received(LinphoneChatRoom *cr, const LinphoneAddress *remoteAddr, bool_t isComposing) {
	NOTIFY_IF_EXIST(IsComposingReceived, is_composing_received, cr, remoteAddr, isComposing)
}

void linphone_chat_room_notify_message_received(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
	NOTIFY_IF_EXIST(MessageReceived, message_received, cr, msg)
}

void linphone_chat_room_notify_participant_added(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
	NOTIFY_IF_EXIST(ParticipantAdded, participant_added, cr, event_log)
}

void linphone_chat_room_notify_participant_removed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
	NOTIFY_IF_EXIST(ParticipantRemoved, participant_removed, cr, event_log)
}

void linphone_chat_room_notify_participant_device_added(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
	NOTIFY_IF_EXIST(ParticipantDeviceAdded, participant_device_added, cr, event_log)
}

void linphone_chat_room_notify_participant_device_removed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
	NOTIFY_IF_EXIST(ParticipantDeviceRemoved, participant_device_removed, cr, event_log)
}

void linphone_chat_room_notify_participant_admin_status_changed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
	NOTIFY_IF_EXIST(ParticipantAdminStatusChanged, participant_admin_status_changed, cr, event_log)
}

void linphone_chat_room_notify_state_changed(LinphoneChatRoom *cr, LinphoneChatRoomState newState) {
	NOTIFY_IF_EXIST(StateChanged, state_changed, cr, newState)
}

void linphone_chat_room_notify_subject_changed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
	NOTIFY_IF_EXIST(SubjectChanged, subject_changed, cr, event_log)
}

void linphone_chat_room_notify_undecryptable_message_received(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
	NOTIFY_IF_EXIST(UndecryptableMessageReceived, undecryptable_message_received, cr, msg)
}

void linphone_chat_room_notify_chat_message_received(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
	NOTIFY_IF_EXIST(ChatMessageReceived, chat_message_received, cr, event_log)
}

void linphone_chat_room_notify_chat_message_sent(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
	NOTIFY_IF_EXIST(ChatMessageSent, chat_message_sent, cr, event_log)
}

void linphone_chat_room_notify_conference_address_generation(LinphoneChatRoom *cr) {
	NOTIFY_IF_EXIST(ConferenceAddressGeneration, conference_address_generation, cr)
}

void linphone_chat_room_notify_participant_device_fetched(LinphoneChatRoom *cr, const LinphoneAddress *participantAddr) {
	NOTIFY_IF_EXIST(ParticipantDeviceFetched, participant_device_fetched, cr, participantAddr)
}

void linphone_chat_room_notify_participants_capabilities_checked(LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsAddr) {
	NOTIFY_IF_EXIST(ParticipantsCapabilitiesChecked, participants_capabilities_checked, cr, deviceAddr, participantsAddr)
}

void linphone_chat_room_notify_chat_message_should_be_stored(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
	NOTIFY_IF_EXIST(ShouldChatMessageBeStored, chat_message_should_be_stored, cr, msg)
}

Ronan's avatar
Ronan committed
506 507 508
// =============================================================================
// Reference and user data handling functions.
// =============================================================================
509

Ronan's avatar
Ronan committed
510
LinphoneChatRoom *linphone_chat_room_ref (LinphoneChatRoom *cr) {
511 512 513 514
	belle_sip_object_ref(cr);
	return cr;
}

Ronan's avatar
Ronan committed
515
void linphone_chat_room_unref (LinphoneChatRoom *cr) {
516 517 518
	belle_sip_object_unref(cr);
}

Ronan's avatar
Ronan committed
519
void *linphone_chat_room_get_user_data (const LinphoneChatRoom *cr) {
520
	return L_GET_USER_DATA_FROM_C_OBJECT(cr);
521 522
}

Ronan's avatar
Ronan committed
523
void linphone_chat_room_set_user_data (LinphoneChatRoom *cr, void *ud) {
524
	L_SET_USER_DATA_FROM_C_OBJECT(cr, ud);
525 526
}

Ronan's avatar
Ronan committed
527 528 529
// =============================================================================
// Constructor and destructor functions.
// =============================================================================
530

531
LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *uri, const char *subject, bool_t fallback) {
532 533 534
	LinphoneAddress *addr = linphone_address_new(uri);
	LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(core, addr);
	linphone_address_unref(addr);
Ronan's avatar
Ronan committed
535
	string from;
536 537 538 539 540 541 542 543 544 545
	if (proxy) {
		const LinphoneAddress *contactAddr = linphone_proxy_config_get_contact(proxy);
		if (contactAddr) {
			char *cFrom = linphone_address_as_string(contactAddr);
			from = string(cFrom);
			bctbx_free(cFrom);
		} else {
			from = L_GET_CPP_PTR_FROM_C_OBJECT(linphone_proxy_config_get_identity_address(proxy))->asString();
		}
	}
546
	if (from.empty())
547
		from = linphone_core_get_primary_contact(core);
548
	LinphonePrivate::IdentityAddress me(from);
549 550
	shared_ptr<LinphonePrivate::ClientGroupChatRoom> cgcr = make_shared<LinphonePrivate::ClientGroupChatRoom>(
		L_GET_CPP_PTR_FROM_C_OBJECT(core), L_C_TO_STRING(uri), me, L_C_TO_STRING(subject));
551
	LinphoneChatRoom *cr = L_INIT(ChatRoom);
552 553 554 555 556 557 558 559 560
	if (fallback) {
		// Create a ClientGroupToBasicChatRoom to handle fallback from ClientGroupChatRoom to BasicGroupChatRoom if
		// only one participant is invited and that it does not support group chat
		L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared<LinphonePrivate::ClientGroupToBasicChatRoom>(cgcr));
		L_GET_PRIVATE(cgcr)->setCallSessionListener(L_GET_PRIVATE_FROM_C_OBJECT(cr));
		L_GET_PRIVATE(cgcr)->setChatRoomListener(L_GET_PRIVATE_FROM_C_OBJECT(cr));
	} else
		L_SET_CPP_PTR_FROM_C_OBJECT(cr, cgcr);
	L_GET_PRIVATE(cgcr)->setState(LinphonePrivate::ChatRoom::State::Instantiated);
561 562 563
	return cr;
}

564 565
LinphoneChatRoom *_linphone_server_group_chat_room_new (LinphoneCore *core, LinphonePrivate::SalCallOp *op) {
	LinphoneChatRoom *cr = L_INIT(ChatRoom);
Ronan's avatar
Ronan committed
566
	L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared<LinphonePrivate::ServerGroupChatRoom>(
567
		L_GET_CPP_PTR_FROM_C_OBJECT(core),
568 569
		op
	));
570 571 572 573 574
	L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated);
	L_GET_PRIVATE_FROM_C_OBJECT(cr, ServerGroupChatRoom)->confirmCreation();
	return cr;
}

575
/* DEPRECATED */
Ronan's avatar
Ronan committed
576
void linphone_chat_room_destroy (LinphoneChatRoom *cr) {
577 578
	linphone_chat_room_unref(cr);
}