mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 19:18:06 +00:00
Handle one-to-one chat rooms and quit the client group chat room when deleting it.
This commit is contained in:
parent
1e350eda33
commit
359b7bde4b
31 changed files with 390 additions and 93 deletions
|
|
@ -80,11 +80,30 @@ static void call_received(SalCallOp *h) {
|
|||
LinphoneAddress *toAddr = linphone_address_new(h->get_to());
|
||||
|
||||
if (_linphone_core_is_conference_creation(lc, toAddr)) {
|
||||
if (sal_address_has_param(h->get_remote_contact_address(), "text"))
|
||||
_linphone_core_create_server_group_chat_room(lc, h);
|
||||
// TODO: handle media conference creation if the "text" feature tag is not present
|
||||
linphone_address_unref(toAddr);
|
||||
linphone_address_unref(fromAddr);
|
||||
if (sal_address_has_param(h->get_remote_contact_address(), "text")) {
|
||||
bool oneToOneChatRoom = false;
|
||||
const char *oneToOneChatRoomStr = sal_custom_header_find(h->get_recv_custom_header(), "One-To-One-Chat-Room");
|
||||
if (oneToOneChatRoomStr && (strcmp(oneToOneChatRoomStr, "true") == 0))
|
||||
oneToOneChatRoom = true;
|
||||
if (oneToOneChatRoom) {
|
||||
IdentityAddress from(h->get_from());
|
||||
list<IdentityAddress> identAddresses = ServerGroupChatRoom::parseResourceLists(h->get_remote_body());
|
||||
if (identAddresses.size() != 1) {
|
||||
h->decline(SalReasonNotAcceptable, nullptr);
|
||||
return;
|
||||
}
|
||||
IdentityAddress confAddr = L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb->findOneToOneConferenceChatRoomAddress(from, identAddresses.front());
|
||||
if (confAddr.isValid()) {
|
||||
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ChatRoomId(confAddr, confAddr));
|
||||
L_GET_PRIVATE(static_pointer_cast<ServerGroupChatRoom>(chatRoom))->confirmRecreation(h);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_linphone_core_create_server_group_chat_room(lc, h);
|
||||
}
|
||||
// TODO: handle media conference creation if the "text" feature tag is not present
|
||||
return;
|
||||
} else if (sal_address_has_param(h->get_remote_contact_address(), "text")) {
|
||||
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ LinphoneChatRoom *_linphone_core_create_server_group_chat_room (LinphoneCore *lc
|
|||
}
|
||||
|
||||
void linphone_core_delete_chat_room (LinphoneCore *, LinphoneChatRoom *cr) {
|
||||
LinphonePrivate::Core::deleteChatRoom(L_GET_CPP_PTR_FROM_C_OBJECT(cr));
|
||||
L_GET_CPP_PTR_FROM_C_OBJECT(cr)->deleteFromDb();
|
||||
}
|
||||
|
||||
LinphoneChatRoom *linphone_core_get_chat_room_from_uri(LinphoneCore *lc, const char *to) {
|
||||
|
|
|
|||
|
|
@ -29,13 +29,15 @@
|
|||
F(Created) \
|
||||
F(TerminationPending) \
|
||||
F(Terminated) \
|
||||
F(CreationFailed)
|
||||
F(CreationFailed) \
|
||||
F(Deleted)
|
||||
|
||||
#define L_ENUM_VALUES_CHAT_ROOM_CAPABILITIES(F) \
|
||||
F(Basic, 1 << 0) \
|
||||
F(RealTimeText, 1 << 1) \
|
||||
F(Conference, 1 << 2) \
|
||||
F(Proxy, 1 << 3) \
|
||||
F(Migratable, 1 << 4)
|
||||
F(Migratable, 1 << 4) \
|
||||
F(OneToOne, 1 << 5)
|
||||
|
||||
#endif // ifndef _L_CHAT_ROOM_ENUMS_H_
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class LINPHONE_PUBLIC AbstractChatRoom : public Object, public CoreAccessor, pub
|
|||
friend class ChatMessage;
|
||||
friend class ChatMessagePrivate;
|
||||
friend class ClientGroupToBasicChatRoomPrivate;
|
||||
friend class Core;
|
||||
friend class CorePrivate;
|
||||
friend class MainDb;
|
||||
friend class ProxyChatRoomPrivate;
|
||||
|
|
@ -66,6 +67,7 @@ public:
|
|||
virtual std::list<std::shared_ptr<EventLog>> getHistoryRange (int begin, int end) const = 0;
|
||||
virtual int getHistorySize () const = 0;
|
||||
|
||||
virtual void deleteFromDb () = 0;
|
||||
virtual void deleteHistory () = 0;
|
||||
|
||||
virtual std::shared_ptr<ChatMessage> getLastChatMessageInHistory () const = 0;
|
||||
|
|
|
|||
|
|
@ -346,6 +346,12 @@ int ChatRoom::getHistorySize () const {
|
|||
return getCore()->getPrivate()->mainDb->getHistorySize(getChatRoomId());
|
||||
}
|
||||
|
||||
void ChatRoom::deleteFromDb () {
|
||||
L_D();
|
||||
Core::deleteChatRoom(this->getSharedFromThis());
|
||||
d->setState(ChatRoom::State::Deleted);
|
||||
}
|
||||
|
||||
void ChatRoom::deleteHistory () {
|
||||
getCore()->getPrivate()->mainDb->cleanHistory(getChatRoomId());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ public:
|
|||
std::list<std::shared_ptr<EventLog>> getHistoryRange (int begin, int end) const override;
|
||||
int getHistorySize () const override;
|
||||
|
||||
void deleteFromDb () override;
|
||||
void deleteHistory () override;
|
||||
|
||||
std::shared_ptr<ChatMessage> getLastChatMessageInHistory () const override;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ public:
|
|||
// ChatRoomListener
|
||||
void onChatRoomInsertRequested (const std::shared_ptr<AbstractChatRoom> &chatRoom) override;
|
||||
void onChatRoomInsertInDatabaseRequested (const std::shared_ptr<AbstractChatRoom> &chatRoom) override;
|
||||
void onChatRoomDeleteRequested (const std::shared_ptr<AbstractChatRoom> &chatRoom) override;
|
||||
|
||||
// CallSessionListener
|
||||
void onCallSessionSetReleased (const std::shared_ptr<const CallSession> &session) override;
|
||||
|
|
@ -50,6 +51,8 @@ public:
|
|||
private:
|
||||
CallSessionListener *callSessionListener = this;
|
||||
ChatRoomListener *chatRoomListener = this;
|
||||
ClientGroupChatRoom::CapabilitiesMask capabilities = ClientGroupChatRoom::Capabilities::Conference;
|
||||
bool deletionOnTerminationEnabled = false;
|
||||
|
||||
L_DECLARE_PUBLIC(ClientGroupChatRoom);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ shared_ptr<CallSession> ClientGroupChatRoomPrivate::createSession () {
|
|||
CallSessionParams csp;
|
||||
csp.addCustomHeader("Require", "recipient-list-invite");
|
||||
csp.addCustomContactParameter("text");
|
||||
if (capabilities & ClientGroupChatRoom::Capabilities::OneToOne)
|
||||
csp.addCustomHeader("One-To-One-Chat-Room", "true");
|
||||
|
||||
shared_ptr<Participant> focus = qConference->getPrivate()->focus;
|
||||
shared_ptr<CallSession> session = focus->getPrivate()->createSession(*q, &csp, false, callSessionListener);
|
||||
|
|
@ -111,6 +113,12 @@ void ClientGroupChatRoomPrivate::onChatRoomInsertInDatabaseRequested (const shar
|
|||
q->getCore()->getPrivate()->insertChatRoomWithDb(chatRoom);
|
||||
}
|
||||
|
||||
void ClientGroupChatRoomPrivate::onChatRoomDeleteRequested (const shared_ptr<AbstractChatRoom> &chatRoom) {
|
||||
L_Q();
|
||||
q->getCore()->deleteChatRoom(q->getSharedFromThis());
|
||||
setState(ClientGroupChatRoom::State::Deleted);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ClientGroupChatRoomPrivate::onCallSessionSetReleased (const shared_ptr<const CallSession> &session) {
|
||||
|
|
@ -164,6 +172,7 @@ ClientGroupChatRoom::ClientGroupChatRoom (
|
|||
const shared_ptr<Core> &core,
|
||||
const ChatRoomId &chatRoomId,
|
||||
shared_ptr<Participant> &me,
|
||||
AbstractChatRoom::CapabilitiesMask capabilities,
|
||||
const string &subject,
|
||||
list<shared_ptr<Participant>> &&participants,
|
||||
unsigned int lastNotifyId
|
||||
|
|
@ -189,7 +198,8 @@ shared_ptr<Core> ClientGroupChatRoom::getCore () const {
|
|||
}
|
||||
|
||||
ClientGroupChatRoom::CapabilitiesMask ClientGroupChatRoom::getCapabilities () const {
|
||||
return Capabilities::Conference;
|
||||
L_D();
|
||||
return d->capabilities;
|
||||
}
|
||||
|
||||
bool ClientGroupChatRoom::hasBeenLeft () const {
|
||||
|
|
@ -208,6 +218,16 @@ const IdentityAddress &ClientGroupChatRoom::getConferenceAddress () const {
|
|||
return RemoteConference::getConferenceAddress();
|
||||
}
|
||||
|
||||
void ClientGroupChatRoom::deleteFromDb () {
|
||||
L_D();
|
||||
if (!hasBeenLeft()) {
|
||||
d->deletionOnTerminationEnabled = true;
|
||||
leave();
|
||||
return;
|
||||
}
|
||||
d->chatRoomListener->onChatRoomDeleteRequested(getSharedFromThis());
|
||||
}
|
||||
|
||||
void ClientGroupChatRoom::addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) {
|
||||
list<IdentityAddress> addresses;
|
||||
addresses.push_back(addr);
|
||||
|
|
@ -231,6 +251,19 @@ void ClientGroupChatRoom::addParticipants (
|
|||
return;
|
||||
}
|
||||
|
||||
if ((getState() == ChatRoom::State::Created) && (d->capabilities & ClientGroupChatRoom::Capabilities::OneToOne)) {
|
||||
lError() << "Cannot add more participants to a OneToOne ClientGroupChatRoom";
|
||||
return;
|
||||
}
|
||||
|
||||
if ((getState() == ChatRoom::State::Instantiated)
|
||||
&& (addressesList.size() == 1)
|
||||
&& (linphone_config_get_bool(linphone_core_get_config(L_GET_C_BACK_PTR(getCore())),
|
||||
"misc", "one_to_one_chat_room_enabled", TRUE))
|
||||
) {
|
||||
d->capabilities |= ClientGroupChatRoom::Capabilities::OneToOne;
|
||||
}
|
||||
|
||||
Content content;
|
||||
content.setBody(getResourceLists(addressesList));
|
||||
content.setContentType("application/resource-lists+xml");
|
||||
|
|
@ -372,6 +405,11 @@ void ClientGroupChatRoom::onConferenceCreated (const IdentityAddress &addr) {
|
|||
d->chatRoomListener->onChatRoomInsertRequested(getSharedFromThis());
|
||||
}
|
||||
|
||||
void ClientGroupChatRoom::onConferenceKeywordsChanged (const vector<string> &keywords) {
|
||||
L_D();
|
||||
d->capabilities |= ClientGroupChatRoom::Capabilities::OneToOne;
|
||||
}
|
||||
|
||||
void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) {
|
||||
L_D();
|
||||
L_D_T(RemoteConference, dConference);
|
||||
|
|
@ -382,6 +420,10 @@ void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) {
|
|||
time(nullptr),
|
||||
d->chatRoomId
|
||||
));
|
||||
if (d->deletionOnTerminationEnabled) {
|
||||
d->deletionOnTerminationEnabled = false;
|
||||
d->chatRoomListener->onChatRoomDeleteRequested(getSharedFromThis());
|
||||
}
|
||||
}
|
||||
|
||||
void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class ClientGroupChatRoomPrivate;
|
|||
class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference {
|
||||
friend class BasicToClientGroupChatRoomPrivate;
|
||||
friend class ClientGroupToBasicChatRoomPrivate;
|
||||
friend class Core;
|
||||
|
||||
public:
|
||||
L_OVERRIDE_SHARED_FROM_THIS(ClientGroupChatRoom);
|
||||
|
|
@ -48,6 +49,7 @@ public:
|
|||
const std::shared_ptr<Core> &core,
|
||||
const ChatRoomId &chatRoomId,
|
||||
std::shared_ptr<Participant> &me,
|
||||
AbstractChatRoom::CapabilitiesMask capabilities,
|
||||
const std::string &subject,
|
||||
std::list<std::shared_ptr<Participant>> &&participants,
|
||||
unsigned int lastNotifyId
|
||||
|
|
@ -63,6 +65,8 @@ public:
|
|||
bool canHandleParticipants () const override;
|
||||
bool canHandleCpim () const override;
|
||||
|
||||
void deleteFromDb () override;
|
||||
|
||||
void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override;
|
||||
void addParticipants (const std::list<IdentityAddress> &addresses, const CallSessionParams *params, bool hasMedia) override;
|
||||
|
||||
|
|
@ -88,6 +92,7 @@ private:
|
|||
// ALL METHODS AFTER THIS POINT.
|
||||
|
||||
void onConferenceCreated (const IdentityAddress &addr) override;
|
||||
void onConferenceKeywordsChanged (const std::vector<std::string> &keywords) override;
|
||||
void onConferenceTerminated (const IdentityAddress &addr) override;
|
||||
void onFirstNotifyReceived (const IdentityAddress &addr) override;
|
||||
void onParticipantAdded (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) override;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,12 @@ public:
|
|||
q->getCore()->getPrivate()->insertChatRoomWithDb(q->getSharedFromThis());
|
||||
}
|
||||
|
||||
void onChatRoomDeleteRequested (const shared_ptr<AbstractChatRoom> &chatRoom) override {
|
||||
L_Q();
|
||||
q->getCore()->deleteChatRoom(q->getSharedFromThis());
|
||||
setState(AbstractChatRoom::State::Deleted);
|
||||
}
|
||||
|
||||
void onCallSessionSetReleased (const std::shared_ptr<const CallSession> &session) override {
|
||||
if (!(chatRoom->getCapabilities() & ChatRoom::Capabilities::Conference))
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -190,6 +190,11 @@ int ProxyChatRoom::getHistorySize () const {
|
|||
return d->chatRoom->getHistorySize();
|
||||
}
|
||||
|
||||
void ProxyChatRoom::deleteFromDb () {
|
||||
L_D();
|
||||
d->chatRoom->deleteFromDb();
|
||||
}
|
||||
|
||||
void ProxyChatRoom::deleteHistory () {
|
||||
L_D();
|
||||
d->chatRoom->deleteHistory();
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public:
|
|||
std::list<std::shared_ptr<EventLog>> getHistoryRange (int begin, int end) const override;
|
||||
int getHistorySize () const override;
|
||||
|
||||
void deleteFromDb () override;
|
||||
void deleteHistory () override;
|
||||
|
||||
std::shared_ptr<ChatMessage> getLastChatMessageInHistory () const override;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public:
|
|||
|
||||
void confirmCreation ();
|
||||
void confirmJoining (SalCallOp *op);
|
||||
void confirmRecreation (SalCallOp *op);
|
||||
|
||||
IdentityAddress generateConferenceAddress (const std::shared_ptr<Participant> &me) const;
|
||||
|
||||
|
|
@ -43,10 +44,9 @@ public:
|
|||
void update (SalCallOp *op);
|
||||
|
||||
void dispatchMessage (const IdentityAddress &fromAddress, const Content &content);
|
||||
|
||||
void setConferenceAddress (const IdentityAddress &conferenceAddress);
|
||||
void setParticipantDevices (const IdentityAddress &addr, const std::list<IdentityAddress> &devices);
|
||||
void addCompatibleParticipants (const IdentityAddress &deviceAddr, const std::list<IdentityAddress> &participantCompatible);
|
||||
void addCompatibleParticipants (const IdentityAddress &deviceAddr, const std::list<IdentityAddress> &compatibleParticipants);
|
||||
|
||||
LinphoneReason onSipMessageReceived (SalOp *op, const SalMessage *message) override;
|
||||
|
||||
|
|
@ -63,12 +63,14 @@ private:
|
|||
// CallSessionListener
|
||||
void onCallSessionStateChanged (
|
||||
const std::shared_ptr<const CallSession> &session,
|
||||
CallSession::State state,
|
||||
CallSession::State newState,
|
||||
const std::string &message
|
||||
) override;
|
||||
|
||||
std::list<std::shared_ptr<Participant>> removedParticipants;
|
||||
ChatRoomListener *chatRoomListener = this;
|
||||
ServerGroupChatRoom::CapabilitiesMask capabilities = ServerGroupChatRoom::Capabilities::Conference;
|
||||
bool joiningPendingAfterCreation = false;
|
||||
|
||||
L_DECLARE_PUBLIC(ServerGroupChatRoom);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ void ServerGroupChatRoomPrivate::confirmCreation () {}
|
|||
|
||||
void ServerGroupChatRoomPrivate::confirmJoining (SalCallOp *) {}
|
||||
|
||||
void ServerGroupChatRoomPrivate::confirmRecreation (SalCallOp *) {}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
IdentityAddress ServerGroupChatRoomPrivate::generateConferenceAddress (const shared_ptr<Participant> &me) const {
|
||||
|
|
@ -110,6 +112,7 @@ LocalConference(core, IdentityAddress(op->get_to()), nullptr) {
|
|||
ServerGroupChatRoom::ServerGroupChatRoom (
|
||||
const shared_ptr<Core> &core,
|
||||
const IdentityAddress &peerAddress,
|
||||
AbstractChatRoom::CapabilitiesMask capabilities,
|
||||
const string &subject,
|
||||
list<shared_ptr<Participant>> &&participants,
|
||||
unsigned int lastNotifyId
|
||||
|
|
|
|||
|
|
@ -39,11 +39,16 @@ public:
|
|||
ServerGroupChatRoom (
|
||||
const std::shared_ptr<Core> &core,
|
||||
const IdentityAddress &peerAddress,
|
||||
AbstractChatRoom::CapabilitiesMask capabilities,
|
||||
const std::string &subject,
|
||||
std::list<std::shared_ptr<Participant>> &&participants,
|
||||
unsigned int lastNotifyId
|
||||
);
|
||||
|
||||
std::shared_ptr<Core> getCore () const;
|
||||
|
||||
std::shared_ptr<Participant> findParticipant (const std::shared_ptr<const CallSession> &session) const;
|
||||
|
||||
CapabilitiesMask getCapabilities () const override;
|
||||
bool hasBeenLeft () const override;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "linphone/utils/general.h"
|
||||
|
||||
|
|
@ -36,6 +37,7 @@ class IdentityAddress;
|
|||
class ConferenceListener {
|
||||
public:
|
||||
virtual void onConferenceCreated (const IdentityAddress &addr) = 0;
|
||||
virtual void onConferenceKeywordsChanged (const std::vector<std::string> &keywords) {}
|
||||
virtual void onConferenceTerminated (const IdentityAddress &addr) = 0;
|
||||
virtual void onFirstNotifyReceived (const IdentityAddress &addr) = 0;
|
||||
virtual void onParticipantAdded (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) = 0;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public:
|
|||
void notifyFullState (const std::string ¬ify, const std::shared_ptr<ParticipantDevice> &device);
|
||||
void notifyAllExcept (const std::string ¬ify, const std::shared_ptr<Participant> &exceptParticipant);
|
||||
void notifyAll (const std::string ¬ify);
|
||||
std::string createNotifyFullState (int notifyId = -1);
|
||||
std::string createNotifyFullState (int notifyId = -1, bool oneToOne = false);
|
||||
std::string createNotifyMultipart (int notifyId);
|
||||
std::string createNotifyParticipantAdded (const Address &addr, int notifyId = -1);
|
||||
std::string createNotifyParticipantRemoved (const Address &addr, int notifyId = -1);
|
||||
|
|
|
|||
|
|
@ -107,13 +107,17 @@ string LocalConferenceEventHandlerPrivate::createNotify (ConferenceType confInfo
|
|||
return notify.str();
|
||||
}
|
||||
|
||||
string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId) {
|
||||
string LocalConferenceEventHandlerPrivate::createNotifyFullState (int notifyId, bool oneToOne) {
|
||||
string entity = conf->getConferenceAddress().asString();
|
||||
string subject = conf->getSubject();
|
||||
ConferenceType confInfo = ConferenceType(entity);
|
||||
UsersType users;
|
||||
ConferenceDescriptionType confDescr = ConferenceDescriptionType();
|
||||
confDescr.setSubject(subject);
|
||||
if (oneToOne) {
|
||||
KeywordsType keywords(sizeof(char), "one-to-one");
|
||||
confDescr.setKeywords(keywords);
|
||||
}
|
||||
confInfo.setUsers(users);
|
||||
confInfo.setConferenceDescription((const ConferenceDescriptionType) confDescr);
|
||||
|
||||
|
|
@ -357,18 +361,13 @@ string LocalConferenceEventHandlerPrivate::createNotifyParticipantDeviceRemoved
|
|||
LocalConferenceEventHandler::LocalConferenceEventHandler (LocalConference *localConference, unsigned int notify) :
|
||||
Object(*new LocalConferenceEventHandlerPrivate) {
|
||||
L_D();
|
||||
xercesc::XMLPlatformUtils::Initialize();
|
||||
d->conf = localConference;
|
||||
d->lastNotify = notify;
|
||||
}
|
||||
|
||||
LocalConferenceEventHandler::~LocalConferenceEventHandler () {
|
||||
xercesc::XMLPlatformUtils::Terminate();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) {
|
||||
void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev, bool oneToOne) {
|
||||
L_D();
|
||||
const LinphoneAddress *lAddr = linphone_event_get_from(lev);
|
||||
char *addrStr = linphone_address_as_string(lAddr);
|
||||
|
|
@ -396,7 +395,7 @@ void LocalConferenceEventHandler::subscribeReceived (LinphoneEvent *lev) {
|
|||
device->setConferenceSubscribeEvent(lev);
|
||||
if (lastNotify == 0) {
|
||||
lInfo() << "Sending initial notify of conference:" << d->conf->getConferenceAddress().asString() << " to: " << device->getAddress().asString();
|
||||
d->notifyFullState(d->createNotifyFullState(static_cast<int>(d->lastNotify)), device);
|
||||
d->notifyFullState(d->createNotifyFullState(static_cast<int>(d->lastNotify), oneToOne), device);
|
||||
} else if (lastNotify < d->lastNotify) {
|
||||
lInfo() << "Sending all missed notify [" << lastNotify << "-" << d->lastNotify <<
|
||||
"] for conference:" << d->conf->getConferenceAddress().asString() <<
|
||||
|
|
|
|||
|
|
@ -42,9 +42,8 @@ class LocalConferenceEventHandlerPrivate;
|
|||
class LocalConferenceEventHandler : public Object {
|
||||
public:
|
||||
LocalConferenceEventHandler (LocalConference *localConference, unsigned int notify = 0);
|
||||
~LocalConferenceEventHandler ();
|
||||
|
||||
void subscribeReceived (LinphoneEvent *lev);
|
||||
void subscribeReceived (LinphoneEvent *lev, bool oneToOne = false);
|
||||
std::shared_ptr<ConferenceParticipantEvent> notifyParticipantAdded (const Address &addr);
|
||||
std::shared_ptr<ConferenceParticipantEvent> notifyParticipantRemoved (const Address &addr);
|
||||
std::shared_ptr<ConferenceParticipantEvent> notifyParticipantSetAdmin (const Address &addr, bool isAdmin);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "linphone/utils/utils.h"
|
||||
|
||||
#include "conference/remote-conference.h"
|
||||
|
|
@ -53,20 +55,30 @@ void RemoteConferenceEventHandlerPrivate::simpleNotifyReceived (const string &xm
|
|||
|
||||
IdentityAddress entityAddress(confInfo->getEntity().c_str());
|
||||
if (entityAddress == chatRoomId.getPeerAddress()) {
|
||||
if (
|
||||
confInfo->getConferenceDescription().present() &&
|
||||
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().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);
|
||||
}
|
||||
}
|
||||
if (confInfo->getVersion().present())
|
||||
lastNotify = confInfo->getVersion().get();
|
||||
|
||||
|
|
@ -215,7 +227,6 @@ void RemoteConferenceEventHandlerPrivate::onRegistrationStateChanged (LinphonePr
|
|||
RemoteConferenceEventHandler::RemoteConferenceEventHandler (RemoteConference *remoteConference) :
|
||||
Object(*new RemoteConferenceEventHandlerPrivate) {
|
||||
L_D();
|
||||
xercesc::XMLPlatformUtils::Initialize();
|
||||
d->conf = remoteConference;
|
||||
d->conf->getCore()->getPrivate()->registerListener(d);
|
||||
}
|
||||
|
|
@ -223,7 +234,6 @@ Object(*new RemoteConferenceEventHandlerPrivate) {
|
|||
RemoteConferenceEventHandler::~RemoteConferenceEventHandler () {
|
||||
L_D();
|
||||
d->conf->getCore()->getPrivate()->unregisterListener(d);
|
||||
xercesc::XMLPlatformUtils::Terminate();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "content/content.h"
|
||||
#include "content/content-type.h"
|
||||
#include "handlers/local-conference-event-handler.h"
|
||||
#include "local-conference-p.h"
|
||||
#include "participant-p.h"
|
||||
|
|
@ -63,20 +65,25 @@ void LocalConference::removeParticipant (const shared_ptr<const Participant> &pa
|
|||
}
|
||||
}
|
||||
|
||||
list<IdentityAddress> LocalConference::parseResourceLists (const string &xmlBody) {
|
||||
istringstream data(xmlBody);
|
||||
unique_ptr<Xsd::ResourceLists::ResourceLists> rl = LinphonePrivate::Xsd::ResourceLists::parseResourceLists(
|
||||
data,
|
||||
Xsd::XmlSchema::Flags::dont_validate
|
||||
);
|
||||
list<IdentityAddress> addresses = list<IdentityAddress>();
|
||||
for (const auto &l : rl->getList()) {
|
||||
for (const auto &entry : l.getEntry()) {
|
||||
IdentityAddress addr(entry.getUri());
|
||||
addresses.push_back(addr);
|
||||
list<IdentityAddress> LocalConference::parseResourceLists (const Content &content) {
|
||||
if ((content.getContentType() == ContentType::ResourceLists)
|
||||
&& (content.getContentDisposition() == "recipient-list")
|
||||
) {
|
||||
istringstream data(content.getBodyAsString());
|
||||
unique_ptr<Xsd::ResourceLists::ResourceLists> rl(Xsd::ResourceLists::parseResourceLists(
|
||||
data,
|
||||
Xsd::XmlSchema::Flags::dont_validate
|
||||
));
|
||||
list<IdentityAddress> addresses;
|
||||
for (const auto &l : rl->getList()) {
|
||||
for (const auto &entry : l.getEntry()) {
|
||||
IdentityAddress addr(entry.getUri());
|
||||
addresses.push_back(move(addr));
|
||||
}
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
return addresses;
|
||||
return list<IdentityAddress>();
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
class Content;
|
||||
class LocalConferencePrivate;
|
||||
|
||||
class LocalConference : public Conference {
|
||||
|
|
@ -39,7 +40,7 @@ public:
|
|||
void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override;
|
||||
void removeParticipant (const std::shared_ptr<const Participant> &participant) override;
|
||||
|
||||
std::list<IdentityAddress> parseResourceLists (const std::string &xmlBody);
|
||||
static std::list<IdentityAddress> parseResourceLists (const Content &content);
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(LocalConference);
|
||||
|
|
|
|||
|
|
@ -252,21 +252,12 @@ void Core::deleteChatRoom (const shared_ptr<const AbstractChatRoom> &chatRoom) {
|
|||
CorePrivate *d = chatRoom->getCore()->getPrivate();
|
||||
|
||||
const ChatRoomId &chatRoomId = chatRoom->getChatRoomId();
|
||||
auto it = d->chatRoomsById.find(chatRoomId);
|
||||
if (it != d->chatRoomsById.end()) {
|
||||
|
||||
// TODO: Remove me later.
|
||||
auto it = find_if(
|
||||
d->chatRooms.begin(), d->chatRooms.end(),
|
||||
[&chatRoomId](const shared_ptr<AbstractChatRoom> &chatRoom) {
|
||||
return chatRoom->getChatRoomId() == chatRoomId;
|
||||
}
|
||||
);
|
||||
|
||||
// FIXME: Use this code in the future. (Wait for signals.)
|
||||
// auto it = find(d->chatRooms.begin(), d->chatRooms.end(), chatRoom);
|
||||
// L_ASSERT(it != d->chatRooms.end());
|
||||
d->chatRooms.erase(it);
|
||||
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);
|
||||
d->mainDb->deleteChatRoom(chatRoomId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <mediastreamer2/mscommon.h>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
|
||||
#include "call/call.h"
|
||||
#include "core/core-listener.h"
|
||||
|
|
@ -52,7 +53,7 @@ void CorePrivate::init () {
|
|||
uri = q->getDataPath() + LINPHONE_DB;
|
||||
}
|
||||
|
||||
lInfo() << "Opening " LINPHONE_DB "...";
|
||||
lInfo() << "Opening linphone database: " << uri;
|
||||
if (!mainDb->connect(backend, uri))
|
||||
lFatal() << "Unable to open linphone database.";
|
||||
|
||||
|
|
@ -91,10 +92,13 @@ void CorePrivate::notifyRegistrationStateChanged (LinphoneProxyConfig *cfg, Linp
|
|||
|
||||
// =============================================================================
|
||||
|
||||
Core::Core () : Object(*new CorePrivate) {}
|
||||
Core::Core () : Object(*new CorePrivate) {
|
||||
xercesc::XMLPlatformUtils::Initialize();
|
||||
}
|
||||
|
||||
Core::~Core () {
|
||||
lInfo() << "Destroying core: " << this;
|
||||
xercesc::XMLPlatformUtils::Terminate();
|
||||
}
|
||||
|
||||
shared_ptr<Core> Core::create (LinphoneCore *cCore) {
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ private:
|
|||
long long selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const;
|
||||
long long selectChatRoomId (const ChatRoomId &chatRoomId) const;
|
||||
long long selectChatRoomParticipantId (long long chatRoomId, long long participantSipAddressId) const;
|
||||
long long selectOneToOneChatRoomId (long long sipAddressIdA, long long sipAddressIdB) const;
|
||||
|
||||
void deleteContents (long long messageEventId);
|
||||
void deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId);
|
||||
|
|
|
|||
|
|
@ -266,10 +266,7 @@ long long MainDbPrivate::insertChatRoom (const shared_ptr<AbstractChatRoom> &cha
|
|||
|
||||
const tm &creationTime = Utils::getTimeTAsTm(chatRoom->getCreationTime());
|
||||
// Remove capabilities like `Proxy`.
|
||||
const int &capabilities = chatRoom->getCapabilities() & ChatRoom::CapabilitiesMask({
|
||||
ChatRoom::Capabilities::Basic, ChatRoom::Capabilities::RealTimeText,
|
||||
ChatRoom::Capabilities::Conference, ChatRoom::Capabilities::Migratable
|
||||
});
|
||||
const int &capabilities = chatRoom->getCapabilities() & ~ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::Proxy);
|
||||
|
||||
const string &subject = chatRoom->getSubject();
|
||||
const int &flags = chatRoom->hasBeenLeft();
|
||||
|
|
@ -409,6 +406,18 @@ long long MainDbPrivate::selectChatRoomParticipantId (long long chatRoomId, long
|
|||
return session->got_data() ? id : -1;
|
||||
}
|
||||
|
||||
long long MainDbPrivate::selectOneToOneChatRoomId (long long sipAddressIdA, long long sipAddressIdB) const {
|
||||
long long id;
|
||||
soci::session *session = dbSession.getBackendSession<soci::session>();
|
||||
*session << "SELECT chat_room_id"
|
||||
" FROM one_to_one_chat_room"
|
||||
" WHERE participant_a_sip_address_id IN (:sipAddressIdA, :sipAddressIdB)"
|
||||
" AND participant_b_sip_address_id IN (:sipAddressIdABis, :sipAddressIdBBis)",
|
||||
soci::into(id),
|
||||
soci::use(sipAddressIdA), soci::use(sipAddressIdB), soci::use(sipAddressIdA), soci::use(sipAddressIdB);
|
||||
return session->got_data() ? id : -1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void MainDbPrivate::deleteContents (long long messageEventId) {
|
||||
|
|
@ -1372,6 +1381,26 @@ void MainDb::init () {
|
|||
" ON DELETE CASCADE"
|
||||
") " + charset;
|
||||
|
||||
if (linphone_core_conference_server_enabled(getCore()->getCCore())) {
|
||||
*session <<
|
||||
"CREATE TABLE IF NOT EXISTS one_to_one_chat_room ("
|
||||
" chat_room_id" + primaryKeyStr("BIGINT UNSIGNED") + ","
|
||||
|
||||
" participant_a_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL,"
|
||||
" participant_b_sip_address_id" + primaryKeyRefStr("BIGINT UNSIGNED") + " NOT NULL,"
|
||||
|
||||
" FOREIGN KEY (chat_room_id)"
|
||||
" REFERENCES chat_room(id)"
|
||||
" ON DELETE CASCADE,"
|
||||
" FOREIGN KEY (participant_a_sip_address_id)"
|
||||
" REFERENCES sip_address(id)"
|
||||
" ON DELETE CASCADE,"
|
||||
" FOREIGN KEY (participant_b_sip_address_id)"
|
||||
" REFERENCES sip_address(id)"
|
||||
" ON DELETE CASCADE"
|
||||
") " + charset;
|
||||
}
|
||||
|
||||
*session <<
|
||||
"CREATE TABLE IF NOT EXISTS chat_room_participant ("
|
||||
" id" + primaryKeyStr("BIGINT UNSIGNED") + ","
|
||||
|
|
@ -2433,6 +2462,7 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms () const {
|
|||
core,
|
||||
chatRoomId,
|
||||
me,
|
||||
capabilities,
|
||||
subject,
|
||||
move(participants),
|
||||
lastNotifyId
|
||||
|
|
@ -2447,6 +2477,7 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms () const {
|
|||
chatRoom = make_shared<ServerGroupChatRoom>(
|
||||
core,
|
||||
chatRoomId.getPeerAddress(),
|
||||
capabilities,
|
||||
subject,
|
||||
move(participants),
|
||||
lastNotifyId
|
||||
|
|
@ -2600,17 +2631,6 @@ IdentityAddress MainDb::findOneToOneConferenceChatRoomAddress (
|
|||
const IdentityAddress &participantA,
|
||||
const IdentityAddress &participantB
|
||||
) const {
|
||||
static const string query = "SELECT sip_address.value"
|
||||
" FROM chat_room, sip_address"
|
||||
" WHERE capabilities = " + Utils::toString(static_cast<int>(ChatRoom::Capabilities::Conference)) +
|
||||
" AND (SELECT COUNT(*) FROM chat_room_participant WHERE chat_room_id = chat_room.id) = 2"
|
||||
" AND (SELECT COUNT(*) FROM chat_room_participant WHERE chat_room_id = chat_room.id AND participant_sip_address_id IN ("
|
||||
" (SELECT id FROM sip_address WHERE value = :participantSipAddressA),"
|
||||
" (SELECT id FROM sip_address WHERE value = :participantSipAddressB)"
|
||||
" )) = 2"
|
||||
" AND sip_address.id = peer_sip_address_id"
|
||||
" LIMIT 1";
|
||||
|
||||
L_D();
|
||||
|
||||
if (!isConnected()) {
|
||||
|
|
@ -2618,24 +2638,63 @@ IdentityAddress MainDb::findOneToOneConferenceChatRoomAddress (
|
|||
return IdentityAddress();
|
||||
}
|
||||
|
||||
string chatRoomAddress;
|
||||
|
||||
L_BEGIN_LOG_EXCEPTION
|
||||
|
||||
soci::session *session = d->dbSession.getBackendSession<soci::session>();
|
||||
soci::transaction tr(*session);
|
||||
|
||||
const string &participantSipAddressA = participantA.asString();
|
||||
const string &participantSipAddressB = participantB.asString();
|
||||
const long long &participantASipAddressId = d->selectSipAddressId(participantA.asString());
|
||||
const long long &participantBSipAddressId = d->selectSipAddressId(participantB.asString());
|
||||
if ((participantASipAddressId == -1) || (participantBSipAddressId == -1))
|
||||
return IdentityAddress();
|
||||
|
||||
string chatRoomAddress;
|
||||
const long long &chatRoomId = d->selectOneToOneChatRoomId(participantASipAddressId, participantBSipAddressId);
|
||||
|
||||
*session << query, soci::use(participantSipAddressA), soci::use(participantSipAddressB), soci::into(chatRoomAddress);
|
||||
|
||||
return IdentityAddress(chatRoomAddress);
|
||||
*session << "SELECT sip_address.value"
|
||||
" FROM chat_room, sip_address"
|
||||
" WHERE chat_room.id = :chatRoomId AND peer_sip_address_id = sip_address.id",
|
||||
soci::use(chatRoomId), soci::into(chatRoomAddress);
|
||||
|
||||
L_END_LOG_EXCEPTION
|
||||
|
||||
// Soci error.
|
||||
return IdentityAddress();
|
||||
return IdentityAddress(chatRoomAddress);
|
||||
}
|
||||
|
||||
void MainDb::insertOneToOneConferenceChatRoom (const shared_ptr<AbstractChatRoom> &chatRoom) {
|
||||
L_D();
|
||||
L_ASSERT(linphone_core_conference_server_enabled(chatRoom->getCore()->getCCore()));
|
||||
L_ASSERT(chatRoom->getCapabilities() & ChatRoom::Capabilities::OneToOne);
|
||||
|
||||
if (!isConnected()) {
|
||||
lWarning() << "Unable to insert one to one conference chat room. Not connected.";
|
||||
return;
|
||||
}
|
||||
|
||||
L_BEGIN_LOG_EXCEPTION
|
||||
|
||||
soci::session *session = d->dbSession.getBackendSession<soci::session>();
|
||||
soci::transaction tr(*session);
|
||||
|
||||
const list<shared_ptr<Participant>> &participants = chatRoom->getParticipants();
|
||||
const long long &participantASipAddressId = d->selectSipAddressId(participants.front()->getAddress().asString());
|
||||
const long long &participantBSipAddressId = d->selectSipAddressId(participants.back()->getAddress().asString());
|
||||
L_ASSERT(participantASipAddressId != -1);
|
||||
L_ASSERT(participantBSipAddressId != -1);
|
||||
|
||||
long long chatRoomId = d->selectOneToOneChatRoomId(participantASipAddressId, participantBSipAddressId);
|
||||
if (chatRoomId == -1) {
|
||||
chatRoomId = d->selectChatRoomId(chatRoom->getChatRoomId());
|
||||
*session << "INSERT INTO one_to_one_chat_room ("
|
||||
" chat_room_id, participant_a_sip_address_id, participant_b_sip_address_id"
|
||||
") VALUES (:chatRoomId, :participantASipAddressId, :participantBSipAddressId)",
|
||||
soci::use(chatRoomId), soci::use(participantASipAddressId), soci::use(participantBSipAddressId);
|
||||
}
|
||||
|
||||
tr.commit();
|
||||
|
||||
L_END_LOG_EXCEPTION
|
||||
}
|
||||
|
||||
void MainDb::enableChatRoomMigration (const ChatRoomId &chatRoomId, bool enable) {
|
||||
|
|
|
|||
|
|
@ -130,6 +130,8 @@ public:
|
|||
const IdentityAddress &participantB
|
||||
) const;
|
||||
|
||||
void insertOneToOneConferenceChatRoom (const std::shared_ptr<AbstractChatRoom> &chatRoom);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Other.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -449,6 +449,7 @@ public:
|
|||
|
||||
private:
|
||||
void onConferenceCreated (const IdentityAddress &addr) override;
|
||||
void onConferenceKeywordsChanged (const vector<string> &keywords) override;
|
||||
void onConferenceTerminated (const IdentityAddress &addr) override;
|
||||
void onFirstNotifyReceived (const IdentityAddress &addr) override;
|
||||
void onParticipantAdded (const shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) override;
|
||||
|
|
@ -463,6 +464,7 @@ public:
|
|||
map<string, bool> participants;
|
||||
map<string, int> participantDevices;
|
||||
string confSubject;
|
||||
bool oneToOne = false;
|
||||
};
|
||||
|
||||
ConferenceEventTester::ConferenceEventTester (const shared_ptr<Core> &core, const Address &confAddr)
|
||||
|
|
@ -476,6 +478,13 @@ ConferenceEventTester::~ConferenceEventTester () {
|
|||
|
||||
void ConferenceEventTester::onConferenceCreated (const IdentityAddress &addr) {}
|
||||
|
||||
void ConferenceEventTester::onConferenceKeywordsChanged (const vector<string> &keywords) {
|
||||
for (const auto &k : keywords) {
|
||||
if (k == "one-to-one")
|
||||
oneToOne = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ConferenceEventTester::onConferenceTerminated (const IdentityAddress &addr) {}
|
||||
|
||||
void ConferenceEventTester::onFirstNotifyReceived (const IdentityAddress &addr) {}
|
||||
|
|
@ -1277,6 +1286,42 @@ void send_device_removed_notify() {
|
|||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
void one_to_one_keyword () {
|
||||
LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc");
|
||||
LinphoneCoreManager *pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
|
||||
char *identityStr = linphone_address_as_string(pauline->identity);
|
||||
Address addr(identityStr);
|
||||
bctbx_free(identityStr);
|
||||
shared_ptr<ConferenceEventTester> tester = make_shared<ConferenceEventTester>(marie->lc->cppPtr, addr);
|
||||
shared_ptr<LocalConference> localConf = make_shared<LocalConference>(pauline->lc->cppPtr, addr, nullptr);
|
||||
LinphoneAddress *cBobAddr = linphone_core_interpret_url(marie->lc, bobUri);
|
||||
char *bobAddrStr = linphone_address_as_string(cBobAddr);
|
||||
Address bobAddr(bobAddrStr);
|
||||
bctbx_free(bobAddrStr);
|
||||
linphone_address_unref(cBobAddr);
|
||||
|
||||
CallSessionParams params;
|
||||
localConf->addParticipant(bobAddr, ¶ms, false);
|
||||
LocalConferenceEventHandlerPrivate *localHandlerPrivate = L_GET_PRIVATE(
|
||||
L_ATTR_GET(L_GET_PRIVATE(localConf), eventHandler)
|
||||
);
|
||||
const_cast<IdentityAddress &>(localConf->getConferenceAddress()) = addr;
|
||||
string notify = localHandlerPrivate->createNotifyFullState(-1, true);
|
||||
|
||||
const_cast<IdentityAddress &>(tester->handler->getChatRoomId().getPeerAddress()) = addr;
|
||||
tester->handler->notifyReceived(notify);
|
||||
|
||||
BC_ASSERT_EQUAL(tester->participantDevices.size(), 1, int, "%d");
|
||||
BC_ASSERT_TRUE(tester->participantDevices.find(bobAddr.asString()) != tester->participantDevices.end());
|
||||
BC_ASSERT_EQUAL(tester->participantDevices.find(bobAddr.asString())->second, 0, int, "%d");
|
||||
BC_ASSERT_TRUE(tester->oneToOne);
|
||||
|
||||
tester = nullptr;
|
||||
localConf = nullptr;
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
test_t conference_event_tests[] = {
|
||||
TEST_NO_TAG("First notify parsing", first_notify_parsing),
|
||||
TEST_NO_TAG("First notify parsing wrong conf", first_notify_parsing_wrong_conf),
|
||||
|
|
@ -1292,7 +1337,8 @@ test_t conference_event_tests[] = {
|
|||
TEST_NO_TAG("Send participant unadmined notify", send_unadmined_notify),
|
||||
TEST_NO_TAG("Send subject changed notify", send_subject_changed_notify),
|
||||
TEST_NO_TAG("Send device added notify", send_device_added_notify),
|
||||
TEST_NO_TAG("Send device removed notify", send_device_removed_notify)
|
||||
TEST_NO_TAG("Send device removed notify", send_device_removed_notify),
|
||||
TEST_NO_TAG("one-to-one keyword", one_to_one_keyword)
|
||||
};
|
||||
|
||||
test_suite_t conference_event_test_suite = {
|
||||
|
|
|
|||
|
|
@ -93,6 +93,9 @@ static void chat_room_state_changed (LinphoneChatRoom *cr, LinphoneChatRoomState
|
|||
case LinphoneChatRoomStateCreationFailed:
|
||||
manager->stat.number_of_LinphoneChatRoomStateCreationFailed++;
|
||||
break;
|
||||
case LinphoneChatRoomStateDeleted:
|
||||
manager->stat.number_of_LinphoneChatRoomStateDeleted++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2033,10 +2036,72 @@ static void group_chat_room_send_file (void) {
|
|||
group_chat_room_send_file_with_or_without_text(FALSE);
|
||||
}
|
||||
|
||||
static void group_chat_room_send_file_plus_text(void) {
|
||||
static void group_chat_room_send_file_plus_text (void) {
|
||||
group_chat_room_send_file_with_or_without_text(TRUE);
|
||||
}
|
||||
|
||||
static void group_chat_room_unique_one_to_one_chat_room (void) {
|
||||
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
|
||||
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
|
||||
bctbx_list_t *coresManagerList = NULL;
|
||||
bctbx_list_t *participantsAddresses = NULL;
|
||||
coresManagerList = bctbx_list_append(coresManagerList, marie);
|
||||
coresManagerList = bctbx_list_append(coresManagerList, pauline);
|
||||
bctbx_list_t *coresList = init_core_for_conference(coresManagerList);
|
||||
start_core_for_conference(coresManagerList);
|
||||
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc)));
|
||||
stats initialMarieStats = marie->stat;
|
||||
stats initialPaulineStats = pauline->stat;
|
||||
|
||||
// Marie creates a new group chat room
|
||||
const char *initialSubject = "Pauline";
|
||||
LinphoneChatRoom *marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, -1);
|
||||
BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(marieCr) & LinphoneChatRoomCapabilitiesOneToOne);
|
||||
|
||||
LinphoneAddress *confAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr));
|
||||
|
||||
// Check that the chat room is correctly created on Pauline's side and that the participants are added
|
||||
LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline, &initialPaulineStats, confAddr, initialSubject, 1, 0);
|
||||
BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(paulineCr) & LinphoneChatRoomCapabilitiesOneToOne);
|
||||
|
||||
// Marie sends a message
|
||||
const char *message = "Hello";
|
||||
_send_message(marieCr, message);
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageDelivered, initialMarieStats.number_of_LinphoneMessageDelivered + 1, 10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 1, 10000));
|
||||
BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(pauline->stat.last_received_chat_message), message);
|
||||
|
||||
// Marie deletes the chat room
|
||||
linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
|
||||
|
||||
// Marie creates the chat room again
|
||||
initialMarieStats = marie->stat;
|
||||
initialPaulineStats = pauline->stat;
|
||||
participantsAddresses = bctbx_list_append(NULL, linphone_address_new(linphone_core_get_identity(pauline->lc)));
|
||||
marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, -1);
|
||||
|
||||
// Marie sends a new message
|
||||
message = "Hey again";
|
||||
_send_message(marieCr, message);
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageDelivered, initialMarieStats.number_of_LinphoneMessageDelivered + 1, 10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 1, 10000));
|
||||
BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(pauline->stat.last_received_chat_message), message);
|
||||
|
||||
// Check that the created address is the same as before
|
||||
const LinphoneAddress *newConfAddr = linphone_chat_room_get_conference_address(marieCr);
|
||||
BC_ASSERT_TRUE(linphone_address_weak_equal(confAddr, newConfAddr));
|
||||
|
||||
// Clean db from chat room
|
||||
linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
|
||||
linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
|
||||
|
||||
linphone_address_unref(confAddr);
|
||||
bctbx_list_free(coresList);
|
||||
bctbx_list_free(coresManagerList);
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
test_t group_chat_tests[] = {
|
||||
TEST_TWO_TAGS("Group chat room creation server", group_chat_room_creation_server, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Send message", group_chat_room_send_message, "Server", "LeaksMemory"),
|
||||
|
|
@ -2062,7 +2127,8 @@ test_t group_chat_tests[] = {
|
|||
TEST_TWO_TAGS("Migrate basic chat room to client group chat room failure", group_chat_room_migrate_from_basic_to_client_fail, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Migrate basic chat room to client group chat room not needed", group_chat_donot_room_migrate_from_basic_chat_room, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Send file", group_chat_room_send_file, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Send file + text", group_chat_room_send_file_plus_text, "Server", "LeaksMemory")
|
||||
TEST_TWO_TAGS("Send file + text", group_chat_room_send_file_plus_text, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Unique one-to-one chatroom", group_chat_room_unique_one_to_one_chat_room, "Server", "LeaksMemory")
|
||||
};
|
||||
|
||||
test_suite_t group_chat_test_suite = {
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ typedef struct _stats {
|
|||
int number_of_LinphoneChatRoomStateTerminationPending;
|
||||
int number_of_LinphoneChatRoomStateTerminated;
|
||||
int number_of_LinphoneChatRoomStateCreationFailed;
|
||||
int number_of_LinphoneChatRoomStateDeleted;
|
||||
|
||||
int number_of_IframeDecoded;
|
||||
|
||||
|
|
@ -331,6 +332,7 @@ void linphone_core_manager_restart(LinphoneCoreManager *mgr, bool_t check_for_pr
|
|||
void linphone_core_manager_uninit(LinphoneCoreManager *mgr);
|
||||
void linphone_core_manager_wait_for_stun_resolution(LinphoneCoreManager *mgr);
|
||||
void linphone_core_manager_destroy(LinphoneCoreManager* mgr);
|
||||
void linphone_core_manager_delete_chat_room (LinphoneCoreManager *mgr, LinphoneChatRoom *cr, bctbx_list_t *coresList);
|
||||
|
||||
void reset_counters( stats* counters);
|
||||
|
||||
|
|
|
|||
|
|
@ -534,6 +534,12 @@ void linphone_core_manager_destroy(LinphoneCoreManager* mgr) {
|
|||
ms_free(mgr);
|
||||
}
|
||||
|
||||
void linphone_core_manager_delete_chat_room (LinphoneCoreManager *mgr, LinphoneChatRoom *cr, bctbx_list_t *coresList) {
|
||||
stats mgrStats = mgr->stat;
|
||||
linphone_core_delete_chat_room(mgr->lc, cr);
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &mgr->stat.number_of_LinphoneChatRoomStateDeleted, mgrStats.number_of_LinphoneChatRoomStateDeleted + 1, 10000));
|
||||
}
|
||||
|
||||
int liblinphone_tester_ipv6_available(void){
|
||||
if (liblinphonetester_ipv6) {
|
||||
struct addrinfo *ai=bctbx_ip_address_to_addrinfo(AF_INET6,SOCK_STREAM,"2a01:e00::2",53);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue