Commit e1122d15 authored by Benjamin REIS's avatar Benjamin REIS

add multipart notify support for conference events

parent cf7c300b
......@@ -2142,10 +2142,16 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve
IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(from))
));
if (chatRoom)
L_GET_PRIVATE(static_pointer_cast<ClientGroupChatRoom>(chatRoom))->notifyReceived(
linphone_content_get_string_buffer(body)
);
if (chatRoom) {
if (linphone_content_is_multipart(body))
L_GET_PRIVATE(static_pointer_cast<ClientGroupChatRoom>(chatRoom))->multipartNotifyReceived(
linphone_content_get_string_buffer(body)
);
else
L_GET_PRIVATE(static_pointer_cast<ClientGroupChatRoom>(chatRoom))->notifyReceived(
linphone_content_get_string_buffer(body)
);
}
}
}
......
......@@ -34,6 +34,7 @@ public:
std::list<Address> cleanAddressesList (const std::list<Address> &addresses) const;
std::shared_ptr<CallSession> createSession ();
void notifyReceived (const std::string &body);
void multipartNotifyReceived (const std::string &body);
private:
L_DECLARE_PUBLIC(ClientGroupChatRoom);
......
......@@ -74,6 +74,11 @@ void ClientGroupChatRoomPrivate::notifyReceived (const string &body) {
qConference->getPrivate()->eventHandler->notifyReceived(body);
}
void ClientGroupChatRoomPrivate::multipartNotifyReceived (const string &body) {
L_Q_T(RemoteConference, qConference);
qConference->getPrivate()->eventHandler->multipartNotifyReceived(body);
}
// =============================================================================
ClientGroupChatRoom::ClientGroupChatRoom (
......
......@@ -37,6 +37,7 @@ public:
void notifyAllExcept (const std::string &notify, const std::shared_ptr<Participant> &exceptParticipant);
void notifyAll (const std::string &notify);
std::string createNotifyFullState (int notifyId = -1);
std::string createNotifyMultipart (int notifyId);
std::string createNotifyParticipantAdded (const Address &addr, int notifyId = -1);
std::string createNotifyParticipantRemoved (const Address &addr, int notifyId = -1);
std::string createNotifyParticipantAdmined (const Address &addr, bool isAdmin, int notifyId = -1);
......@@ -51,6 +52,7 @@ private:
unsigned int lastNotify = 0;
std::string createNotify (Xsd::ConferenceInfo::ConferenceType confInfo, int notifyId = -1, bool isFullState = false);
std::string createNotifySubjectChanged (const std::string &subject, int notifyId = -1);
void notifyParticipant (const std::string &notify, const std::shared_ptr<Participant> &participant);
void notifyParticipantDevice (const std::string &notify, const std::shared_ptr<ParticipantDevice> &device);
......
......@@ -21,8 +21,15 @@
#include "linphone/utils/utils.h"
#include "chat/chat-room/chat-room-id.h"
#include "conference/local-conference.h"
#include "conference/participant-p.h"
#include "content/content-manager.h"
#include "content/content-type.h"
#include "content/content.h"
#include "core/core-p.h"
#include "db/main-db.h"
#include "event-log/events.h"
#include "local-conference-event-handler-p.h"
#include "logger/logger.h"
#include "object/object-p.h"
......@@ -128,6 +135,94 @@ string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId)
return createNotify(confInfo, notifyId, true);
}
string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId) {
list<shared_ptr<EventLog>> events = conf->getCore()->getPrivate()->mainDb->getConferenceNotifiedEvents(
ChatRoomId(conf->getConferenceAddress(), conf->getConferenceAddress()),
static_cast<unsigned int>(notifyId)
);
list<Content> contents;
for (const auto &eventLog : events) {
Content content;
content.setContentType(ContentType("application","conference-info"));
string body;
shared_ptr<ConferenceNotifiedEvent> notifiedEvent = static_pointer_cast<ConferenceNotifiedEvent>(eventLog);
int eventNotifyId = static_cast<int>(notifiedEvent->getNotifyId());
switch (eventLog->getType()) {
case EventLog::Type::ConferenceParticipantAdded: {
shared_ptr<ConferenceParticipantEvent> addedEvent = static_pointer_cast<ConferenceParticipantEvent>(eventLog);
body = createNotifyParticipantAdded(
addedEvent->getParticipantAddress(),
eventNotifyId
);
} break;
case EventLog::Type::ConferenceParticipantRemoved: {
shared_ptr<ConferenceParticipantEvent> removedEvent = static_pointer_cast<ConferenceParticipantEvent>(eventLog);
body = createNotifyParticipantRemoved(
removedEvent->getParticipantAddress(),
eventNotifyId
);
} break;
case EventLog::Type::ConferenceParticipantSetAdmin: {
shared_ptr<ConferenceParticipantEvent> setAdminEvent = static_pointer_cast<ConferenceParticipantEvent>(eventLog);
body = createNotifyParticipantAdmined(
setAdminEvent->getParticipantAddress(),
true,
eventNotifyId
);
} break;
case EventLog::Type::ConferenceParticipantUnsetAdmin: {
shared_ptr<ConferenceParticipantEvent> unsetAdminEvent = static_pointer_cast<ConferenceParticipantEvent>(eventLog);
body = createNotifyParticipantAdmined(
unsetAdminEvent->getParticipantAddress(),
false,
eventNotifyId
);
} break;
case EventLog::Type::ConferenceParticipantDeviceAdded: {
shared_ptr<ConferenceParticipantDeviceEvent> deviceAddedEvent = static_pointer_cast<ConferenceParticipantDeviceEvent>(eventLog);
body = createNotifyParticipantDeviceAdded(
deviceAddedEvent->getParticipantAddress(),
deviceAddedEvent->getDeviceAddress(),
eventNotifyId
);
} break;
case EventLog::Type::ConferenceParticipantDeviceRemoved: {
shared_ptr<ConferenceParticipantDeviceEvent> deviceRemovedEvent = static_pointer_cast<ConferenceParticipantDeviceEvent>(eventLog);
body = createNotifyParticipantDeviceRemoved(
deviceRemovedEvent->getParticipantAddress(),
deviceRemovedEvent->getDeviceAddress(),
eventNotifyId
);
} break;
case EventLog::Type::ConferenceSubjectChanged: {
shared_ptr<ConferenceSubjectEvent> subjectEvent = static_pointer_cast<ConferenceSubjectEvent>(eventLog);
body = createNotifySubjectChanged(
subjectEvent->getSubject(),
eventNotifyId
);
} break;
default:
// We should never pass here!
L_ASSERT(false);
continue;
}
content.setBody(body);
contents.push_back(content);
}
ContentManager contentManager;
Content multipart = contentManager.contentsListToMultipart(contents);
return multipart.getBodyAsString();
}
string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdded (const Address &addr, int notifyId) {
string entity = conf->getConferenceAddress().asStringUriOnly();
ConferenceType confInfo = ConferenceType(entity);
......@@ -190,8 +285,11 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantAdmined (const
}
string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (int notifyId) {
return createNotifySubjectChanged(conf->getSubject(), notifyId);
}
string LocalConferenceEventHandlerPrivate::createNotifySubjectChanged (const string &subject, int notifyId) {
string entity = conf->getConferenceAddress().asStringUriOnly();
string subject = conf->getSubject();
ConferenceType confInfo = ConferenceType(entity);
ConferenceDescriptionType confDescr = ConferenceDescriptionType();
confDescr.setSubject(subject);
......@@ -291,7 +389,7 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) {
} else if (lastNotify < d->lastNotify) {
lInfo() << "Sending all missed notify for conference:" << d->conf->getConferenceAddress().asStringUriOnly() <<
" from: " << lastNotify << " to: " << participant->getAddress().asString();
// TODO : send all missed notify from lastNotify to d->lastNotify
d->notifyParticipantDevice(d->createNotifyMultipart(static_cast<int>(lastNotify)), device);
} else if (lastNotify > d->lastNotify) {
lError() << "last notify received by client: [" << lastNotify <<"] for conference:" <<
d->conf->getConferenceAddress().asStringUriOnly() <<
......
......@@ -32,6 +32,8 @@ LINPHONE_BEGIN_NAMESPACE
class RemoteConferenceEventHandlerPrivate : public ObjectPrivate {
private:
void simpleNotifyReceived (const std::string &xmlBody);
ChatRoomId chatRoomId;
RemoteConference *conf = nullptr;
......
......@@ -20,6 +20,8 @@
#include "linphone/utils/utils.h"
#include "conference/remote-conference.h"
#include "content/content-manager.h"
#include "content/content.h"
#include "core/core.h"
#include "logger/logger.h"
#include "remote-conference-event-handler-p.h"
......@@ -38,46 +40,7 @@ using namespace Xsd::ConferenceInfo;
// -----------------------------------------------------------------------------
RemoteConferenceEventHandler::RemoteConferenceEventHandler (RemoteConference *remoteConference) :
Object(*new RemoteConferenceEventHandlerPrivate) {
L_D();
xercesc::XMLPlatformUtils::Initialize();
d->conf = remoteConference;
// TODO : d->lastNotify = lastNotify
}
RemoteConferenceEventHandler::~RemoteConferenceEventHandler () {
xercesc::XMLPlatformUtils::Terminate();
}
// -----------------------------------------------------------------------------
void RemoteConferenceEventHandler::subscribe (const ChatRoomId &chatRoomId) {
L_D();
d->chatRoomId = chatRoomId;
LinphoneAddress *lAddr = linphone_address_new(d->chatRoomId.getPeerAddress().asString().c_str());
d->lev = linphone_core_create_subscribe(d->conf->getCore()->getCCore(), lAddr, "conference", 600);
linphone_event_add_custom_header(d->lev, "Last-Notify-Version", Utils::toString(d->lastNotify).c_str());
linphone_address_unref(lAddr);
linphone_event_set_internal(d->lev, TRUE);
linphone_event_set_user_data(d->lev, this);
linphone_event_send_subscribe(d->lev, nullptr);
}
void RemoteConferenceEventHandler::unsubscribe () {
L_D();
if (d->lev) {
linphone_event_terminate(d->lev);
d->lev = nullptr;
}
}
void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
L_D();
lInfo() << "NOTIFY received for conference: (remote=" << d->chatRoomId.getPeerAddress().asString() <<
", local=" << d->chatRoomId.getLocalAddress().asString() << ").";
void RemoteConferenceEventHandlerPrivate::simpleNotifyReceived (const string &xmlBody) {
istringstream data(xmlBody);
unique_ptr<ConferenceType> confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate);
time_t tm = time(nullptr);
......@@ -86,10 +49,10 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
bool isFullState = (confInfo->getState() == StateType::full);
ConferenceListener *confListener = static_cast<ConferenceListener *>(d->conf);
ConferenceListener *confListener = static_cast<ConferenceListener *>(conf);
// TODO: Temporary workaround, remove me.
const IdentityAddress &peerAddress = d->chatRoomId.getPeerAddress();
const IdentityAddress &peerAddress = chatRoomId.getPeerAddress();
IdentityAddress entityAddress(confInfo->getEntity().c_str());
IdentityAddress peerAddressWorkaround = peerAddress;
peerAddressWorkaround.setDomain(entityAddress.getDomain());
......@@ -101,20 +64,20 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
confListener->onSubjectChanged(
make_shared<ConferenceSubjectEvent>(
tm,
d->chatRoomId,
d->lastNotify,
chatRoomId,
lastNotify,
confInfo->getConferenceDescription().get().getSubject().get()
),
isFullState
);
if (confInfo->getVersion().present())
d->lastNotify = confInfo->getVersion().get();
lastNotify = confInfo->getVersion().get();
if (!confInfo->getUsers().present())
return;
for (const auto &user : confInfo->getUsers()->getUser()) {
LinphoneAddress *cAddr = linphone_core_interpret_url(d->conf->getCore()->getCCore(), user.getEntity()->c_str());
LinphoneAddress *cAddr = linphone_core_interpret_url(conf->getCore()->getCCore(), user.getEntity()->c_str());
char *cAddrStr = linphone_address_as_string(cAddr);
Address addr(cAddrStr);
bctbx_free(cAddrStr);
......@@ -123,8 +86,8 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
make_shared<ConferenceParticipantEvent>(
EventLog::Type::ConferenceParticipantRemoved,
tm,
d->chatRoomId,
d->lastNotify,
chatRoomId,
lastNotify,
addr
),
isFullState
......@@ -145,8 +108,8 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
make_shared<ConferenceParticipantEvent>(
EventLog::Type::ConferenceParticipantAdded,
tm,
d->chatRoomId,
d->lastNotify,
chatRoomId,
lastNotify,
addr
),
isFullState
......@@ -157,8 +120,8 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
make_shared<ConferenceParticipantEvent>(
isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin,
tm,
d->chatRoomId,
d->lastNotify,
chatRoomId,
lastNotify,
addr
),
isFullState
......@@ -174,8 +137,8 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
make_shared<ConferenceParticipantDeviceEvent>(
EventLog::Type::ConferenceParticipantDeviceRemoved,
tm,
d->chatRoomId,
d->lastNotify,
chatRoomId,
lastNotify,
addr,
gruu
),
......@@ -186,8 +149,8 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
make_shared<ConferenceParticipantDeviceEvent>(
EventLog::Type::ConferenceParticipantDeviceAdded,
tm,
d->chatRoomId,
d->lastNotify,
chatRoomId,
lastNotify,
addr,
gruu
),
......@@ -200,7 +163,67 @@ void RemoteConferenceEventHandler::notifyReceived (const string &xmlBody) {
}
if (isFullState)
confListener->onFirstNotifyReceived(d->chatRoomId.getPeerAddress());
confListener->onFirstNotifyReceived(chatRoomId.getPeerAddress());
}
}
// -----------------------------------------------------------------------------
RemoteConferenceEventHandler::RemoteConferenceEventHandler (RemoteConference *remoteConference) :
Object(*new RemoteConferenceEventHandlerPrivate) {
L_D();
xercesc::XMLPlatformUtils::Initialize();
d->conf = remoteConference;
// TODO : d->lastNotify = lastNotify
}
RemoteConferenceEventHandler::~RemoteConferenceEventHandler () {
xercesc::XMLPlatformUtils::Terminate();
}
// -----------------------------------------------------------------------------
void RemoteConferenceEventHandler::subscribe (const ChatRoomId &chatRoomId) {
L_D();
d->chatRoomId = chatRoomId;
LinphoneAddress *lAddr = linphone_address_new(d->chatRoomId.getPeerAddress().asString().c_str());
d->lev = linphone_core_create_subscribe(d->conf->getCore()->getCCore(), lAddr, "conference", 600);
linphone_event_add_custom_header(d->lev, "Last-Notify-Version", Utils::toString(d->lastNotify).c_str());
linphone_address_unref(lAddr);
linphone_event_set_internal(d->lev, TRUE);
linphone_event_set_user_data(d->lev, this);
linphone_event_send_subscribe(d->lev, nullptr);
}
void RemoteConferenceEventHandler::unsubscribe () {
L_D();
if (d->lev) {
linphone_event_terminate(d->lev);
d->lev = nullptr;
}
}
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);
ContentManager manager;
list<Content> contents = manager.multipartToContentLists(multipart);
for (const auto &content : contents) {
d->simpleNotifyReceived(content.getBodyAsString());
}
}
......
......@@ -37,6 +37,7 @@ public:
void subscribe (const ChatRoomId &chatRoomId);
void notifyReceived (const std::string &xmlBody);
void multipartNotifyReceived (const std::string &xmlBody);
void unsubscribe ();
const ChatRoomId &getChatRoomId () const;
......
......@@ -57,7 +57,7 @@ void LocalConference::removeParticipant (const shared_ptr<const Participant> &pa
}
}
list<Address> LocalConference::parseResourceLists (string xmlBody) {
list<Address> LocalConference::parseResourceLists (const string &xmlBody) {
istringstream data(xmlBody);
unique_ptr<Xsd::ResourceLists::ResourceLists> rl = LinphonePrivate::Xsd::ResourceLists::parseResourceLists(
data,
......
......@@ -38,7 +38,7 @@ public:
void addParticipant (const Address &addr, const CallSessionParams *params, bool hasMedia) override;
void removeParticipant (const std::shared_ptr<const Participant> &participant) override;
std::list<Address> parseResourceLists (std::string xmlBody);
std::list<Address> parseResourceLists (const std::string &xmlBody);
private:
L_DECLARE_PRIVATE(LocalConference);
......
......@@ -20,12 +20,11 @@
#include <sstream>
#include "belle-sip/belle-sip.h"
#include "content-manager.h"
#include "content-type.h"
#include "linphone/content.h"
#include "linphone/core.h"
#include "logger/logger.h"
#include "private.h"
// =============================================================================
......@@ -35,11 +34,7 @@ using namespace std;
LINPHONE_BEGIN_NAMESPACE
ContentManager::ContentManager (LinphoneCore *core) {
mCore = core;
}
list<Content> ContentManager::multipartToContentLists (Content content) const {
list<Content> ContentManager::multipartToContentLists (const Content &content) const {
belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new_from_buffer((void *)content.getBodyAsString().c_str(), content.getBodyAsString().length(), MULTIPART_BOUNDARY);
belle_sip_object_ref(mpbh);
......@@ -71,7 +66,7 @@ list<Content> ContentManager::multipartToContentLists (Content content) const {
return contentsList;
}
Content ContentManager::contentsListToMultipart (list<Content> contents) const {
Content ContentManager::contentsListToMultipart (const list<Content> &contents) const {
char *desc;
string sub;
belle_sip_memory_body_handler_t *mbh = NULL;
......@@ -99,7 +94,6 @@ Content ContentManager::contentsListToMultipart (list<Content> contents) const {
}
desc = belle_sip_object_to_string(mpbh);
belle_sip_object_unref(mpbh);
belle_sip_object_ref(mbh);
Content retContent = Content();
ContentType type("application", sub);
......
......@@ -22,8 +22,9 @@
#include <list>
#include "linphone/utils/general.h"
#include "content.h"
#include "linphone/types.h"
// =============================================================================
......@@ -31,13 +32,10 @@ LINPHONE_BEGIN_NAMESPACE
class ContentManager {
public:
ContentManager (LinphoneCore *core);
std::list<Content> multipartToContentLists (Content content) const;
Content contentsListToMultipart (std::list<Content> contents) const;
ContentManager () = default;
private:
LinphoneCore *mCore = nullptr;
std::list<Content> multipartToContentLists (const Content &content) const;
Content contentsListToMultipart (const std::list<Content> &contents) const;
};
LINPHONE_END_NAMESPACE
......
......@@ -39,6 +39,7 @@ class IdentityAddress;
class LINPHONE_PUBLIC Core : public Object {
friend class ChatRoom;
friend class ClientGroupChatRoom;
friend class LocalConferenceEventHandlerPrivate;
friend class MainDb;
friend class MainDbEventKey;
......
......@@ -438,7 +438,7 @@ static const char *participant_unadmined_notify = \
static const char *bobUri = "sip:bob@example.com";
static const char *aliceUri = "sip:alice@example.com";
static const char *frankUri = "sip:frank@example.com";
static const char *confUri = "sips:conf233@example.com";
static const char *confUri = "sip:conf233@example.com";
L_ENABLE_ATTR_ACCESS(LocalConferencePrivate, unique_ptr<LocalConferenceEventHandler>, eventHandler);
......@@ -561,7 +561,7 @@ void first_notify_parsing() {
void first_notify_parsing_wrong_conf() {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, "sips:conf322@example.com");
LinphoneAddress *confAddress = linphone_core_interpret_url(marie->lc, "sip:conf322@example.com");
char *confAddressStr = linphone_address_as_string(confAddress);
Address addr(confAddressStr);
bctbx_free(confAddressStr);
......
......@@ -160,10 +160,9 @@ static const char* part4 = \
"</presence>";
void multipart_to_list () {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
ContentManager manager(marie->lc);
ContentManager manager;
Content multipartContent = Content();
Content multipartContent;
multipartContent.setBody(multipart);
multipartContent.setContentType(ContentType("multipart", "related"));
......@@ -240,31 +239,24 @@ void multipart_to_list () {
ms_message("\n\n----- Original part 4 -----");
ms_message("%s", originalStr4.c_str());
BC_ASSERT_TRUE(originalStr4 == generatedStr4);
linphone_core_manager_destroy(marie);
}
void list_to_multipart () {
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
ContentManager manager(marie->lc);
ContentManager manager;
Content content1 = Content();
Content content1;
content1.setBody(part1);
content1.setContentType(ContentType("application", "rlmi+xml"));
Content content2 = Content();
Content content2;
content2.setBody(part2);
content2.setContentType(ContentType("application", "pidf+xml"));
Content content3 = Content();
Content content3;
content3.setBody(part3);
content3.setContentType(ContentType("application", "pidf+xml"));
Content content4 = Content();
Content content4;
content4.setBody(part4);
content4.setContentType(ContentType("application", "pidf+xml"));
list<Content> contents;
contents.push_back(content1);
contents.push_back(content2);
contents.push_back(content3);
contents.push_back(content4);
list<Content> contents = {content1, content2, content3, content4};
Content multipartContent = manager.contentsListToMultipart(contents);
string originalStr(multipart);
......@@ -285,8 +277,6 @@ void list_to_multipart () {
ms_message("\n\n----- Original multipart -----");
ms_message("%s", originalStr.c_str());
BC_ASSERT_TRUE(originalStr == generatedStr);
linphone_core_manager_destroy(marie);
}
test_t content_manager_tests[] = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment