core-chat-room.cpp 10.2 KB
Newer Older
1 2
/*
 * core-chat-room.cpp
3
 * Copyright (C) 2010-2018 Belledonne Communications SARL
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <algorithm>

22
#include "address/identity-address.h"
23
#include "chat/chat-room/basic-chat-room.h"
24
#include "chat/chat-room/basic-to-client-group-chat-room.h"
25 26
#include "chat/chat-room/chat-room-p.h"
#include "chat/chat-room/real-time-text-chat-room.h"
27
#include "conference/participant.h"
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#include "core-p.h"
#include "logger/logger.h"

// TODO: Remove me later.
#include "c-wrapper/c-wrapper.h"

// =============================================================================

using namespace std;

LINPHONE_BEGIN_NAMESPACE

// -----------------------------------------------------------------------------
// Helpers.
// -----------------------------------------------------------------------------

44
// Return the better local address to talk with peer address.
45
static IdentityAddress getDefaultLocalAddress (const shared_ptr<Core> &core, const IdentityAddress &peerAddress) {
46 47 48 49 50 51
	LinphoneCore *cCore = core->getCCore();

	LinphoneAddress *cPeerAddress = linphone_address_new(peerAddress.asString().c_str());
	LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cCore, cPeerAddress);
	linphone_address_unref(cPeerAddress);

52
	IdentityAddress localAddress;
53 54
	if (proxy) {
		char *identity = linphone_address_as_string(linphone_proxy_config_get_identity_address(proxy));
55
		localAddress = IdentityAddress(identity);
56 57
		bctbx_free(identity);
	} else
58
		localAddress = IdentityAddress(linphone_core_get_primary_contact(cCore));
59 60

	return localAddress;
61 62
}

63 64
// -----------------------------------------------------------------------------

65 66
shared_ptr<AbstractChatRoom> CorePrivate::createBasicChatRoom (
	const ChatRoomId &chatRoomId,
67
	ChatRoom::CapabilitiesMask capabilities
68
) {
69 70
	L_Q();

71
	shared_ptr<AbstractChatRoom> chatRoom;
72

73
	if (capabilities & ChatRoom::Capabilities::RealTimeText)
74
		chatRoom.reset(new RealTimeTextChatRoom(q->getSharedFromThis(), chatRoomId));
75
	else {
76
		BasicChatRoom *basicChatRoom = new BasicChatRoom(q->getSharedFromThis(), chatRoomId);
77 78 79 80 81 82
		LinphoneAddress *lAddr = linphone_address_new(chatRoomId.getLocalAddress().asString().c_str());
		LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(q->getCCore(), lAddr);
		linphone_address_unref(lAddr);
		const char *conferenceFactoryUri = nullptr;
		if (proxy)
			conferenceFactoryUri = linphone_proxy_config_get_conference_factory_uri(proxy);
83 84
		if (
			capabilities & ChatRoom::Capabilities::Migratable &&
85
			conferenceFactoryUri &&
86 87
			linphone_config_get_bool(linphone_core_get_config(q->getCCore()),
				"misc", "enable_basic_to_client_group_chat_room_migration", FALSE)
88
		)
89 90 91
			chatRoom.reset(new BasicToClientGroupChatRoom(shared_ptr<BasicChatRoom>(basicChatRoom)));
		else
			chatRoom.reset(basicChatRoom);
92
	}
93

94 95 96
	AbstractChatRoomPrivate *dChatRoom = chatRoom->getPrivate();
	dChatRoom->setState(ChatRoom::State::Instantiated);
	dChatRoom->setState(ChatRoom::State::Created);
97 98 99 100

	return chatRoom;
}

101 102
shared_ptr<AbstractChatRoom> CorePrivate::createClientGroupChatRoom (const string &subject, bool fallback) {
	L_Q();
103 104 105 106 107
	LinphoneChatRoom *lcr = _linphone_client_group_chat_room_new(
		q->getCCore(),
		nullptr,
		L_STRING_TO_C(subject),
		fallback ? TRUE : FALSE
108
	);
109
	return lcr ? L_GET_CPP_PTR_FROM_C_OBJECT(lcr) : nullptr;
110 111
}

112
void CorePrivate::insertChatRoom (const shared_ptr<AbstractChatRoom> &chatRoom) {
113
	L_ASSERT(chatRoom);
114 115 116 117 118 119

	const ChatRoomId &chatRoomId = chatRoom->getChatRoomId();
	auto it = chatRoomsById.find(chatRoomId);
	// Chat room not exist or yes but with the same pointer!
	L_ASSERT(it == chatRoomsById.end() || it->second == chatRoom);
	if (it == chatRoomsById.end()) {
120
		chatRooms.push_back(chatRoom);
121
		chatRoomsById[chatRoomId] = chatRoom;
122
	}
123 124
}

125
void CorePrivate::insertChatRoomWithDb (const shared_ptr<AbstractChatRoom> &chatRoom) {
126
	L_ASSERT(chatRoom->getState() == ChatRoom::State::Created);
127
	mainDb->insertChatRoom(chatRoom);
128 129
}

130
void CorePrivate::loadChatRooms () {
131 132
	chatRooms.clear();
	chatRoomsById.clear();
133 134 135 136
	for (auto &chatRoom : mainDb->getChatRooms())
		insertChatRoom(chatRoom);
}

137 138 139 140 141 142 143 144 145 146 147 148 149 150
void CorePrivate::replaceChatRoom (const shared_ptr<AbstractChatRoom> &replacedChatRoom, const shared_ptr<AbstractChatRoom> &newChatRoom) {
	const ChatRoomId &replacedChatRoomId = replacedChatRoom->getChatRoomId();
	const ChatRoomId &newChatRoomId = newChatRoom->getChatRoomId();
	if (replacedChatRoom->getCapabilities() & ChatRoom::Capabilities::Proxy) {
		chatRooms.remove(newChatRoom);
		chatRoomsById.erase(newChatRoomId);
		chatRoomsById[newChatRoomId] = replacedChatRoom;
	} else {
		chatRooms.remove(replacedChatRoom);
		chatRoomsById.erase(replacedChatRoomId);
		chatRoomsById[newChatRoomId] = newChatRoom;
	}
}

151 152
// -----------------------------------------------------------------------------

153
const list<shared_ptr<AbstractChatRoom>> &Core::getChatRooms () const {
154 155 156 157
	L_D();
	return d->chatRooms;
}

158
shared_ptr<AbstractChatRoom> Core::findChatRoom (const ChatRoomId &chatRoomId) const {
159
	L_D();
160

161 162
	auto it = d->chatRoomsById.find(chatRoomId);
	if (it != d->chatRoomsById.cend())
163 164
		return it->second;

165 166
	lInfo() << "Unable to find chat room in RAM: " << chatRoomId << ".";
	return nullptr;
167 168
}

169
list<shared_ptr<AbstractChatRoom>> Core::findChatRooms (const IdentityAddress &peerAddress) const {
170 171
	L_D();

172
	list<shared_ptr<AbstractChatRoom>> output;
173 174
	copy_if(
		d->chatRooms.begin(), d->chatRooms.end(),
175
		back_inserter(output), [&peerAddress](const shared_ptr<AbstractChatRoom> &chatRoom) {
176 177 178 179 180
			return chatRoom->getPeerAddress() == peerAddress;
		}
	);

	return output;
181 182
}

183
shared_ptr<AbstractChatRoom> Core::findOneToOneChatRoom (
184 185
	const IdentityAddress &localAddress,
	const IdentityAddress &participantAddress
186
) const {
187 188
	L_D();
	for (const auto &chatRoom : d->chatRooms) {
189
		const IdentityAddress &curLocalAddress = chatRoom->getLocalAddress();
190 191 192 193 194 195 196 197 198 199
		ChatRoom::CapabilitiesMask capabilities = chatRoom->getCapabilities();

		// We are looking fo a one to one chatroom
		// Do not return a group chat room that everyone except one person has left
		if (!(capabilities & ChatRoom::Capabilities::OneToOne))
			continue;

		// One to one client group chat room
		// The only participant's address must match the participantAddress argument
		if (
200 201
			(capabilities & ChatRoom::Capabilities::Conference) &&
			!chatRoom->getParticipants().empty() &&
202
			localAddress == curLocalAddress &&
203
			participantAddress.getAddressWithoutGruu() == chatRoom->getParticipants().front()->getAddress()
204 205 206 207 208
		)
			return chatRoom;

		// One to one basic chat room (addresses without gruu)
		// The peer address must match the participantAddress argument
209
		if (
210
			(capabilities & ChatRoom::Capabilities::Basic) &&
211
			localAddress.getAddressWithoutGruu() == curLocalAddress.getAddressWithoutGruu() &&
212
			participantAddress.getAddressWithoutGruu() == chatRoom->getPeerAddress().getAddressWithoutGruu()
213 214 215 216 217 218
		)
			return chatRoom;
	}
	return nullptr;
}

219
shared_ptr<AbstractChatRoom> Core::createClientGroupChatRoom (const string &subject) {
220 221
	L_D();
	return d->createClientGroupChatRoom(subject, true);
222 223
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237
shared_ptr<AbstractChatRoom> Core::onlyGetOrCreateBasicChatRoom (const IdentityAddress &peerAddress, bool isRtt) {
	list<shared_ptr<AbstractChatRoom>> chatRooms = findChatRooms(peerAddress);
	if (!chatRooms.empty())
		return chatRooms.front();

	const ChatRoomId &chatRoomId = ChatRoomId(peerAddress, getDefaultLocalAddress(getSharedFromThis(), peerAddress));
	shared_ptr<AbstractChatRoom> chatRoom;

	BasicChatRoom *basicChatRoom = new BasicChatRoom(getSharedFromThis(), chatRoomId);
	chatRoom.reset(basicChatRoom);

	return chatRoom;
}

238
shared_ptr<AbstractChatRoom> Core::getOrCreateBasicChatRoom (const ChatRoomId &chatRoomId, bool isRtt) {
239 240
	L_D();

241
	shared_ptr<AbstractChatRoom> chatRoom = findChatRoom(chatRoomId);
242 243 244
	if (chatRoom)
		return chatRoom;

245 246 247
	chatRoom = d->createBasicChatRoom(chatRoomId,
		isRtt ? ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::RealTimeText) : ChatRoom::CapabilitiesMask()
	);
248 249 250 251 252 253
	d->insertChatRoom(chatRoom);
	d->insertChatRoomWithDb(chatRoom);

	return chatRoom;
}

254
shared_ptr<AbstractChatRoom> Core::getOrCreateBasicChatRoom (const IdentityAddress &peerAddress, bool isRtt) {
255 256
	L_D();

257
	list<shared_ptr<AbstractChatRoom>> chatRooms = findChatRooms(peerAddress);
258 259 260
	if (!chatRooms.empty())
		return chatRooms.front();

261
	shared_ptr<AbstractChatRoom> chatRoom = d->createBasicChatRoom(
262
		ChatRoomId(peerAddress, getDefaultLocalAddress(getSharedFromThis(), peerAddress)),
263
		isRtt ? ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::RealTimeText) : ChatRoom::CapabilitiesMask()
264
	);
265
	d->insertChatRoom(chatRoom);
266 267 268 269 270
	d->insertChatRoomWithDb(chatRoom);

	return chatRoom;
}

271
shared_ptr<AbstractChatRoom> Core::getOrCreateBasicChatRoomFromUri (const string &peerAddress, bool isRtt) {
272
	LinphoneAddress *address = linphone_core_interpret_url(getCCore(), L_STRING_TO_C(peerAddress));
273 274 275 276 277
	if (!address) {
		lError() << "Cannot make a valid address with: `" << peerAddress << "`.";
		return nullptr;
	}

278
	shared_ptr<AbstractChatRoom> chatRoom = getOrCreateBasicChatRoom(*L_GET_CPP_PTR_FROM_C_OBJECT(address), isRtt);
279 280 281 282
	linphone_address_unref(address);
	return chatRoom;
}

283
void Core::deleteChatRoom (const shared_ptr<const AbstractChatRoom> &chatRoom) {
284
	CorePrivate *d = chatRoom->getCore()->getPrivate();
285 286

	const ChatRoomId &chatRoomId = chatRoom->getChatRoomId();
287 288 289 290 291 292
	auto chatRoomsByIdIt = d->chatRoomsById.find(chatRoomId);
	if (chatRoomsByIdIt != d->chatRoomsById.end()) {
		auto chatRoomsIt = find(d->chatRooms.begin(), d->chatRooms.end(), chatRoom);
		L_ASSERT(chatRoomsIt != d->chatRooms.end());
		d->chatRooms.erase(chatRoomsIt);
		d->chatRoomsById.erase(chatRoomsByIdIt);
293
		d->mainDb->deleteChatRoom(chatRoomId);
294
	}
295 296 297
}

LINPHONE_END_NAMESPACE