remote-conference-event-handler.cpp 9.13 KB
Newer Older
1
/*
2
 * remote-conference-event-handler.cpp
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 <sstream>

22 23 24
#include "linphone/utils/utils.h"

#include "conference/remote-conference.h"
25 26
#include "content/content-manager.h"
#include "content/content.h"
27
#include "core/core-p.h"
28 29
#include "logger/logger.h"
#include "remote-conference-event-handler-p.h"
30 31
#include "xml/conference-info.h"

32 33 34
// TODO: Remove me later.
#include "private.h"

35 36
// =============================================================================

37 38
using namespace std;

39 40
LINPHONE_BEGIN_NAMESPACE

41 42
using namespace Xsd::ConferenceInfo;

43
// -----------------------------------------------------------------------------
44

45
void RemoteConferenceEventHandlerPrivate::simpleNotifyReceived (const string &xmlBody) {
46
	istringstream data(xmlBody);
47
	unique_ptr<ConferenceType> confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate);
48 49 50 51
	time_t tm = time(nullptr);
	if (confInfo->getConferenceDescription()->getFreeText().present())
		tm = static_cast<time_t>(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get()));

52
	bool isFullState = (confInfo->getState() == StateType::full);
53

54
	ConferenceListener *confListener = static_cast<ConferenceListener *>(conf);
55

56
	IdentityAddress entityAddress(confInfo->getEntity().c_str());
57
	if (entityAddress == chatRoomId.getPeerAddress()) {
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
		if (confInfo->getConferenceDescription().present()) {
			if (confInfo->getConferenceDescription().get().getSubject().present() &&
				!confInfo->getConferenceDescription().get().getSubject().get().empty()
			) {
				confListener->onSubjectChanged(
					make_shared<ConferenceSubjectEvent>(
						tm,
						chatRoomId,
						lastNotify,
						confInfo->getConferenceDescription().get().getSubject().get()
					),
					isFullState
				);
			}
			if (confInfo->getConferenceDescription().get().getKeywords().present()
				&& !confInfo->getConferenceDescription().get().getKeywords().get().empty()
			) {
				KeywordsType xmlKeywords = confInfo->getConferenceDescription().get().getKeywords().get();
				vector<string> keywords;
				for (const auto &k : xmlKeywords)
					keywords.push_back(k);
				confListener->onConferenceKeywordsChanged(keywords);
			}
		}
82
		if (confInfo->getVersion().present())
83
			lastNotify = confInfo->getVersion().get();
84

85
		if (!confInfo->getUsers().present())
86 87
			return;

88
		for (const auto &user : confInfo->getUsers()->getUser()) {
89
			LinphoneAddress *cAddr = linphone_core_interpret_url(conf->getCore()->getCCore(), user.getEntity()->c_str());
Ghislain MARY's avatar
Ghislain MARY committed
90 91 92
			char *cAddrStr = linphone_address_as_string(cAddr);
			Address addr(cAddrStr);
			bctbx_free(cAddrStr);
93
			if (user.getState() == StateType::deleted) {
94
				confListener->onParticipantRemoved(
95 96 97
					make_shared<ConferenceParticipantEvent>(
						EventLog::Type::ConferenceParticipantRemoved,
						tm,
98 99
						chatRoomId,
						lastNotify,
100 101 102 103
						addr
					),
					isFullState
				);
104
			} else {
105
				bool isAdmin = false;
106
				if (user.getRoles()) {
107 108 109 110 111 112 113
					for (const auto &entry : user.getRoles()->getEntry()) {
						if (entry == "admin") {
							isAdmin = true;
							break;
						}
					}
				}
114

115
				if (user.getState() == StateType::full) {
116
					confListener->onParticipantAdded(
117 118 119
						make_shared<ConferenceParticipantEvent>(
							EventLog::Type::ConferenceParticipantAdded,
							tm,
120 121
							chatRoomId,
							lastNotify,
122 123 124 125 126 127
							addr
						),
						isFullState
					);
				}

128
				confListener->onParticipantSetAdmin(
129 130
					make_shared<ConferenceParticipantEvent>(
						isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin,
131
						tm,
132 133
						chatRoomId,
						lastNotify,
134
						addr
135 136 137 138
					),
					isFullState
				);

139 140 141 142 143
				for (const auto &endpoint : user.getEndpoint()) {
					if (!endpoint.getEntity().present())
						break;

					Address gruu(endpoint.getEntity().get());
144
					if (endpoint.getState() == StateType::deleted) {
145
						confListener->onParticipantDeviceRemoved(
146 147 148
							make_shared<ConferenceParticipantDeviceEvent>(
								EventLog::Type::ConferenceParticipantDeviceRemoved,
								tm,
149 150
								chatRoomId,
								lastNotify,
151 152 153 154 155
								addr,
								gruu
							),
							isFullState
						);
156
					} else if (endpoint.getState() == StateType::full) {
157
						confListener->onParticipantDeviceAdded(
158 159 160
							make_shared<ConferenceParticipantDeviceEvent>(
								EventLog::Type::ConferenceParticipantDeviceAdded,
								tm,
161 162
								chatRoomId,
								lastNotify,
163 164 165 166 167
								addr,
								gruu
							),
							isFullState
						);
168
					}
169
				}
170
			}
171
			linphone_address_unref(cAddr);
172
		}
173 174

		if (isFullState)
175 176 177 178 179 180
			confListener->onFirstNotifyReceived(chatRoomId.getPeerAddress());
	}
}

// -----------------------------------------------------------------------------

181 182 183
void RemoteConferenceEventHandlerPrivate::subscribe () {
	if (lev || !subscriptionWanted)
		return; // Already subscribed or application did not request subscription
184

185 186
	const string &peerAddress = chatRoomId.getPeerAddress().asString();
	LinphoneAddress *lAddr = linphone_address_new(peerAddress.c_str());
187 188
	LinphoneCore *lc = conf->getCore()->getCCore();
	LinphoneProxyConfig *cfg = linphone_core_lookup_known_proxy(lc, lAddr);
189 190
	if (!cfg || (linphone_proxy_config_get_state(cfg) != LinphoneRegistrationOk)) {
		linphone_address_unref(lAddr);
191
		return;
192
	}
193

194
	lev = linphone_event_ref(linphone_core_create_subscribe(conf->getCore()->getCCore(), lAddr, "conference", 600));
195 196 197 198 199 200 201 202 203 204 205 206 207
	lev->op->set_from(chatRoomId.getLocalAddress().asString().c_str());
	const string &lastNotifyStr = Utils::toString(lastNotify);
	linphone_event_add_custom_header(lev, "Last-Notify-Version", lastNotifyStr.c_str());
	linphone_address_unref(lAddr);
	linphone_event_set_internal(lev, TRUE);
	linphone_event_set_user_data(lev, this);
	lInfo() << "Subscribing to chat room: " << peerAddress << "with last notify: " << lastNotifyStr;
	linphone_event_send_subscribe(lev, nullptr);
}

void RemoteConferenceEventHandlerPrivate::unsubscribe () {
	if (lev) {
		linphone_event_terminate(lev);
208
		linphone_event_unref(lev);
209 210 211 212 213 214
		lev = nullptr;
	}
}

// -----------------------------------------------------------------------------

215 216
void RemoteConferenceEventHandlerPrivate::onNetworkReachable (bool sipNetworkReachable, bool mediaNetworkReachable) {
	if (!sipNetworkReachable)
217 218 219 220 221 222 223 224 225 226
		unsubscribe();
}

void RemoteConferenceEventHandlerPrivate::onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const std::string &message) {
	if (state == LinphoneRegistrationOk)
		subscribe();
}

// -----------------------------------------------------------------------------

227 228 229 230
RemoteConferenceEventHandler::RemoteConferenceEventHandler (RemoteConference *remoteConference) :
Object(*new RemoteConferenceEventHandlerPrivate) {
	L_D();
	d->conf = remoteConference;
231
	d->conf->getCore()->getPrivate()->registerListener(d);
232 233 234
}

RemoteConferenceEventHandler::~RemoteConferenceEventHandler () {
235 236
	L_D();
	d->conf->getCore()->getPrivate()->unregisterListener(d);
237 238 239 240 241 242 243
}

// -----------------------------------------------------------------------------

void RemoteConferenceEventHandler::subscribe (const ChatRoomId &chatRoomId) {
	L_D();
	d->chatRoomId = chatRoomId;
244 245
	d->subscriptionWanted = true;
	d->subscribe();
246 247 248 249
}

void RemoteConferenceEventHandler::unsubscribe () {
	L_D();
250 251
	d->unsubscribe();
	d->subscriptionWanted = false;
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
}

void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
	L_D();

	lInfo() << "NOTIFY received for conference: (remote=" << d->chatRoomId.getPeerAddress().asString() <<
		", local=" << d->chatRoomId.getLocalAddress().asString() << ").";

	d->simpleNotifyReceived(xmlBody);
}

void RemoteConferenceEventHandler::multipartNotifyReceived (const string &xmlBody) {
	L_D();

	lInfo() << "multipart NOTIFY received for conference: (remote=" << d->chatRoomId.getPeerAddress().asString() <<
		", local=" << d->chatRoomId.getLocalAddress().asString() << ").";

	Content multipart;
	multipart.setBody(xmlBody);
271 272

	for (const auto &content : ContentManager::multipartToContentList(multipart))
273
		d->simpleNotifyReceived(content.getBodyAsString());
274 275
}

276 277
// -----------------------------------------------------------------------------

278
const ChatRoomId &RemoteConferenceEventHandler::getChatRoomId () const {
279
	L_D();
280
	return d->chatRoomId;
281 282
}

283 284 285 286 287
unsigned int RemoteConferenceEventHandler::getLastNotify () const {
	L_D();
	return d->lastNotify;
};

288
void RemoteConferenceEventHandler::setLastNotify (unsigned int lastNotify) {
289
	L_D();
290
	d->lastNotify = lastNotify;
291 292
}

293 294 295 296
void RemoteConferenceEventHandler::resetLastNotify () {
	setLastNotify(0);
}

297
LINPHONE_END_NAMESPACE