From 5b31f56f6c1c2d712e540a0b232b6b0db0e52c36 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 19 Dec 2017 11:43:30 +0100 Subject: [PATCH] Handle fallback to basic chat room when a client group chat room is created inviting a single participant that does not support it. --- coreapi/linphonecore.c | 24 ++++-- include/linphone/api/c-chat-room.h | 7 ++ include/linphone/api/c-types.h | 6 ++ include/linphone/core.h | 15 ++++ include/linphone/enums/chat-room-enums.h | 3 +- src/CMakeLists.txt | 1 + src/c-wrapper/api/c-chat-room.cpp | 19 +++-- src/c-wrapper/c-wrapper.h | 1 + src/chat/chat-room/abstract-chat-room-p.h | 4 +- src/chat/chat-room/abstract-chat-room.h | 2 + src/chat/chat-room/chat-room-listener.h | 42 +++++++++++ src/chat/chat-room/client-group-chat-room-p.h | 15 +++- src/chat/chat-room/client-group-chat-room.cpp | 21 ++++-- src/chat/chat-room/client-group-chat-room.h | 2 + .../client-group-to-basic-chat-room.cpp | 73 +++++++++++++++++-- .../client-group-to-basic-chat-room.h | 11 +++ src/chat/chat-room/proxy-chat-room.cpp | 20 ++++- src/chat/chat-room/proxy-chat-room.h | 4 + src/chat/chat-room/server-group-chat-room-p.h | 9 ++- src/core/core.h | 2 + tester/group_chat_tester.c | 45 +++++++++++- tester/rcfiles/chloe_rc | 1 - tester/rcfiles/laure_tcp_rc | 1 - tester/rcfiles/pauline_rc | 1 - 24 files changed, 295 insertions(+), 34 deletions(-) create mode 100644 src/chat/chat-room/chat-room-listener.h diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 183e7b892..79bfde9c3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -50,6 +50,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "bctoolbox/charconv.h" #include "chat/chat-room/client-group-chat-room-p.h" +#include "chat/chat-room/client-group-to-basic-chat-room.h" #include "chat/chat-room/server-group-chat-room-p.h" #include "conference/handlers/remote-conference-event-handler.h" #include "content/content-manager.h" @@ -2141,20 +2142,22 @@ static void linphone_core_internal_notify_received(LinphoneCore *lc, LinphoneEve )); if (chatRoom) { + shared_ptr cgcr; + if (chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Proxy)) + cgcr = static_pointer_cast( + static_pointer_cast(chatRoom)->getProxiedChatRoom()); + else + cgcr = static_pointer_cast(chatRoom); if (linphone_content_is_multipart(body)) { // TODO : migrate to c++ 'Content'. int i = 0; LinphoneContent *part = NULL; while ((part = linphone_content_get_part(body, i))) { i++; - L_GET_PRIVATE(static_pointer_cast(chatRoom))->notifyReceived( - linphone_content_get_string_buffer(part) - ); + L_GET_PRIVATE(cgcr)->notifyReceived(linphone_content_get_string_buffer(part)); } } else - L_GET_PRIVATE(static_pointer_cast(chatRoom))->notifyReceived( - linphone_content_get_string_buffer(body) - ); + L_GET_PRIVATE(cgcr)->notifyReceived(linphone_content_get_string_buffer(body)); } } } @@ -7281,3 +7284,12 @@ bool_t linphone_core_has_crappy_opengl(LinphoneCore *lc) { if (sound_description->flags & DEVICE_HAS_CRAPPY_OPENGL) return TRUE; return FALSE; } + +const char *linphone_core_get_linphone_specs (const LinphoneCore *core) { + return lp_config_get_string(linphone_core_get_config(core), "sip", "linphone_specs", NULL); +} + +void linphone_core_set_linphone_specs (LinphoneCore *core, const char *specs) { + lp_config_set_string(linphone_core_get_config(core), "sip", "linphone_specs", specs); + core->sal->set_contact_linphone_specs(specs); +} diff --git a/include/linphone/api/c-chat-room.h b/include/linphone/api/c-chat-room.h index 77c87cf64..085484ad9 100644 --- a/include/linphone/api/c-chat-room.h +++ b/include/linphone/api/c-chat-room.h @@ -312,6 +312,13 @@ LINPHONE_PUBLIC bool_t linphone_chat_room_can_handle_participants (const Linphon */ LINPHONE_PUBLIC LinphoneParticipant *linphone_chat_room_find_participant (const LinphoneChatRoom *cr, const LinphoneAddress *addr); +/** + * Get the capabilities of a chat room. + * @param[in] cr A LinphoneChatRoom object + * @return The capabilities of the chat room + */ +LINPHONE_PUBLIC LinphoneChatRoomCapabilities linphone_chat_room_get_capabilities (const LinphoneChatRoom *cr); + /** * Get the conference address of the chat room. * @param[in] cr A LinphoneChatRoom object diff --git a/include/linphone/api/c-types.h b/include/linphone/api/c-types.h index a673db45d..15c1945fe 100644 --- a/include/linphone/api/c-types.h +++ b/include/linphone/api/c-types.h @@ -169,6 +169,12 @@ L_DECLARE_C_ENUM(ChatMessageDirection, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION); */ L_DECLARE_C_ENUM(ChatMessageState, L_ENUM_VALUES_CHAT_MESSAGE_STATE); +/** + * LinphoneChatRoomCapabilities is used to indicated the capabilities of a chat room. + * @ingroup chatroom + */ +L_DECLARE_C_ENUM_FIXED_VALUES(ChatRoomCapabilities, L_ENUM_VALUES_CHAT_ROOM_CAPABILITIES); + /** * LinphoneChatRoomState is used to indicate the current state of a chat room. * @ingroup chatroom diff --git a/include/linphone/core.h b/include/linphone/core.h index e6382eb8b..46652ebae 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -4910,6 +4910,21 @@ LINPHONE_PUBLIC bool_t linphone_core_is_content_type_supported(const LinphoneCor */ LINPHONE_PUBLIC void linphone_core_add_content_type_support(LinphoneCore *lc, const char *content_type); +/** + * Get the linphone specs value telling what functionalities the linphone client supports. + * @param[in] core LinphoneCore object + * @return The linphone specs telling what functionalities the linphone client supports + * @ingroup initializing + */ +const char *linphone_core_get_linphone_specs (const LinphoneCore *core); + +/** + * Set the linphone specs value telling what functionalities the linphone client supports. + * @param[in] core LinphoneCore object + * @param[in] specs The linphone specs to set + * @ingroup initializing + */ +void linphone_core_set_linphone_specs (LinphoneCore *core, const char *specs); /** * @addtogroup chatroom diff --git a/include/linphone/enums/chat-room-enums.h b/include/linphone/enums/chat-room-enums.h index 11e1f8fa9..d0fccb39e 100644 --- a/include/linphone/enums/chat-room-enums.h +++ b/include/linphone/enums/chat-room-enums.h @@ -34,6 +34,7 @@ #define L_ENUM_VALUES_CHAT_ROOM_CAPABILITIES(F) \ F(Basic, 1 << 0) \ F(RealTimeText, 1 << 1) \ - F(Conference, 1 << 2) + F(Conference, 1 << 2) \ + F(Proxy, 1 << 3) #endif // ifndef _CHAT_ROOM_ENUMS_H_ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eaa452bfd..1dc090fe6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES chat/chat-room/basic-chat-room.h chat/chat-room/basic-to-client-group-chat-room.h chat/chat-room/chat-room-id.h + chat/chat-room/chat-room-listener.h chat/chat-room/chat-room-p.h chat/chat-room/chat-room.h chat/chat-room/client-group-chat-room-p.h diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 4d3c82e13..453612980 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -29,7 +29,8 @@ #include "c-wrapper/c-wrapper.h" #include "chat/chat-message/chat-message-p.h" #include "chat/chat-room/basic-chat-room.h" -#include "chat/chat-room/client-group-chat-room.h" +#include "chat/chat-room/client-group-chat-room-p.h" +#include "chat/chat-room/client-group-to-basic-chat-room.h" #include "chat/chat-room/real-time-text-chat-room-p.h" #include "chat/chat-room/server-group-chat-room-p.h" #include "conference/participant.h" @@ -264,6 +265,10 @@ LinphoneParticipant *linphone_chat_room_find_participant (const LinphoneChatRoom )); } +LinphoneChatRoomCapabilities linphone_chat_room_get_capabilities (const LinphoneChatRoom *cr) { + return (LinphoneChatRoomCapabilities)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities(); +} + const LinphoneAddress *linphone_chat_room_get_conference_address (const LinphoneChatRoom *cr) { if (cr->conferenceAddressCache) linphone_address_unref(cr->conferenceAddressCache); @@ -388,11 +393,15 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, cons if (from.empty()) from = linphone_core_get_primary_contact(core); LinphonePrivate::IdentityAddress me(from); + // Create a ClientGroupToBasicChatRoom to handle fallback from ClientGroupChatRoom to BasicGroupChatRoom if + // only one participant is invited and that it does not support group chat + shared_ptr cgcr = make_shared( + L_GET_CPP_PTR_FROM_C_OBJECT(core), L_C_TO_STRING(uri), me, L_C_TO_STRING(subject)); + L_GET_PRIVATE(cgcr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared( - L_GET_CPP_PTR_FROM_C_OBJECT(core), L_C_TO_STRING(uri), me, L_C_TO_STRING(subject)) - ); - L_GET_PRIVATE_FROM_C_OBJECT(cr, ChatRoom)->setState(LinphonePrivate::ChatRoom::State::Instantiated); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(cgcr)); + L_GET_PRIVATE(cgcr)->setCallSessionListener(L_GET_PRIVATE_FROM_C_OBJECT(cr)); + L_GET_PRIVATE(cgcr)->setChatRoomListener(L_GET_PRIVATE_FROM_C_OBJECT(cr)); return cr; } diff --git a/src/c-wrapper/c-wrapper.h b/src/c-wrapper/c-wrapper.h index f2e076aab..78ab410f5 100644 --- a/src/c-wrapper/c-wrapper.h +++ b/src/c-wrapper/c-wrapper.h @@ -47,6 +47,7 @@ F(AbstractChatRoom, BasicToClientGroupChatRoom) \ F(AbstractChatRoom, ChatRoom) \ F(AbstractChatRoom, ClientGroupChatRoom) \ + F(AbstractChatRoom, ClientGroupToBasicChatRoom) \ F(AbstractChatRoom, RealTimeTextChatRoom) \ F(AbstractChatRoom, ServerGroupChatRoom) \ F(Call, LocalConferenceCall) \ diff --git a/src/chat/chat-room/abstract-chat-room-p.h b/src/chat/chat-room/abstract-chat-room-p.h index c67fcc794..ec51ab888 100644 --- a/src/chat/chat-room/abstract-chat-room-p.h +++ b/src/chat/chat-room/abstract-chat-room-p.h @@ -21,6 +21,8 @@ #define _ABSTRACT_CHAT_ROOM_P_H_ #include "abstract-chat-room.h" +#include "chat/chat-room/chat-room-listener.h" +#include "conference/session/call-session-listener.h" #include "object/object-p.h" // ============================================================================= @@ -31,7 +33,7 @@ LINPHONE_BEGIN_NAMESPACE class SalOp; -class AbstractChatRoomPrivate : public ObjectPrivate { +class AbstractChatRoomPrivate : public ObjectPrivate, public ChatRoomListener, public CallSessionListener { public: virtual void setCreationTime (time_t creationTime) = 0; virtual void setLastUpdateTime (time_t lastUpdateTime) = 0; diff --git a/src/chat/chat-room/abstract-chat-room.h b/src/chat/chat-room/abstract-chat-room.h index 5a2db3d52..9eb1139a0 100644 --- a/src/chat/chat-room/abstract-chat-room.h +++ b/src/chat/chat-room/abstract-chat-room.h @@ -42,6 +42,8 @@ class LINPHONE_PUBLIC AbstractChatRoom : public Object, public CoreAccessor, pub friend class ProxyChatRoomPrivate; public: + L_OVERRIDE_SHARED_FROM_THIS(AbstractChatRoom); + L_DECLARE_ENUM(Capabilities, L_ENUM_VALUES_CHAT_ROOM_CAPABILITIES); L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_ROOM_STATE); diff --git a/src/chat/chat-room/chat-room-listener.h b/src/chat/chat-room/chat-room-listener.h new file mode 100644 index 000000000..27d58ea10 --- /dev/null +++ b/src/chat/chat-room/chat-room-listener.h @@ -0,0 +1,42 @@ +/* + * chat-room-listener.h + * Copyright (C) 2010-2017 Belledonne Communications SARL + * + * 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. + */ + +#ifndef _CHAT_ROOM_LISTENER_H_ +#define _CHAT_ROOM_LISTENER_H_ + +#include + +#include "chat/chat-room/abstract-chat-room.h" + +// ============================================================================= + +LINPHONE_BEGIN_NAMESPACE + +class ChatRoomListener { +public: + virtual ~ChatRoomListener () = default; + + virtual void onChatRoomInsertRequested (const std::shared_ptr &chatRoom) {} + virtual void onChatRoomInsertInDatabaseRequested (const std::shared_ptr &chatRoom) {} + virtual void onChatRoomDeleteRequested (const std::shared_ptr &chatRoom) {} +}; + +LINPHONE_END_NAMESPACE + +#endif // ifndef _CHAT_ROOM_LISTENER_H_ diff --git a/src/chat/chat-room/client-group-chat-room-p.h b/src/chat/chat-room/client-group-chat-room-p.h index de830bdd6..b3fa88945 100644 --- a/src/chat/chat-room/client-group-chat-room-p.h +++ b/src/chat/chat-room/client-group-chat-room-p.h @@ -22,13 +22,12 @@ #include "chat/chat-room/chat-room-p.h" #include "client-group-chat-room.h" -#include "conference/session/call-session-listener.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class ClientGroupChatRoomPrivate : public ChatRoomPrivate, public CallSessionListener { +class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: ClientGroupChatRoomPrivate () = default; @@ -37,11 +36,21 @@ public: void notifyReceived (const std::string &body); void multipartNotifyReceived (const std::string &body); -private: + void setCallSessionListener (CallSessionListener *listener) { callSessionListener = listener; } + void setChatRoomListener (ChatRoomListener *listener) { chatRoomListener = listener; } + + // ChatRoomListener + void onChatRoomInsertRequested (const std::shared_ptr &chatRoom) override; + void onChatRoomInsertInDatabaseRequested (const std::shared_ptr &chatRoom) override; + // CallSessionListener void onCallSessionSetReleased (const std::shared_ptr &session) override; void onCallSessionStateChanged (const std::shared_ptr &session, LinphoneCallState state, const std::string &message) override; +private: + CallSessionListener *callSessionListener = this; + ChatRoomListener *chatRoomListener = this; + L_DECLARE_PUBLIC(ClientGroupChatRoom); }; diff --git a/src/chat/chat-room/client-group-chat-room.cpp b/src/chat/chat-room/client-group-chat-room.cpp index db27436ee..c2b36ec81 100644 --- a/src/chat/chat-room/client-group-chat-room.cpp +++ b/src/chat/chat-room/client-group-chat-room.cpp @@ -62,7 +62,7 @@ shared_ptr ClientGroupChatRoomPrivate::createSession () { csp.addCustomContactParameter("text"); shared_ptr focus = qConference->getPrivate()->focus; - shared_ptr session = focus->getPrivate()->createSession(*q, &csp, false, this); + shared_ptr session = focus->getPrivate()->createSession(*q, &csp, false, callSessionListener); const Address &myAddress = q->getMe()->getAddress(); Address myCleanedAddress(myAddress); myCleanedAddress.setUriParam("gr"); // Remove gr parameter for INVITE @@ -83,6 +83,18 @@ void ClientGroupChatRoomPrivate::multipartNotifyReceived (const string &body) { // ----------------------------------------------------------------------------- +void ClientGroupChatRoomPrivate::onChatRoomInsertRequested (const shared_ptr &chatRoom) { + L_Q(); + q->getCore()->getPrivate()->insertChatRoom(chatRoom); +} + +void ClientGroupChatRoomPrivate::onChatRoomInsertInDatabaseRequested (const shared_ptr &chatRoom) { + L_Q(); + q->getCore()->getPrivate()->insertChatRoomWithDb(chatRoom); +} + +// ----------------------------------------------------------------------------- + void ClientGroupChatRoomPrivate::onCallSessionSetReleased (const shared_ptr &session) { L_Q_T(RemoteConference, qConference); @@ -335,7 +347,7 @@ void ClientGroupChatRoom::onConferenceCreated (const IdentityAddress &addr) { dConference->focus->getPrivate()->clearDevices(); dConference->focus->getPrivate()->addDevice(addr); d->chatRoomId = ChatRoomId(addr, d->chatRoomId.getLocalAddress()); - getCore()->getPrivate()->insertChatRoom(getSharedFromThis()); + d->chatRoomListener->onChatRoomInsertRequested(getSharedFromThis()); } void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) { @@ -354,9 +366,8 @@ void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) { L_D(); d->setState(ChatRoom::State::Created); - CorePrivate *dCore = getCore()->getPrivate(); - dCore->insertChatRoomWithDb(getSharedFromThis()); - dCore->mainDb->addEvent(make_shared( + d->chatRoomListener->onChatRoomInsertInDatabaseRequested(getSharedFromThis()); + getCore()->getPrivate()->mainDb->addEvent(make_shared( EventLog::Type::ConferenceCreated, time(nullptr), d->chatRoomId diff --git a/src/chat/chat-room/client-group-chat-room.h b/src/chat/chat-room/client-group-chat-room.h index 8d8689cb3..4fc33cc19 100644 --- a/src/chat/chat-room/client-group-chat-room.h +++ b/src/chat/chat-room/client-group-chat-room.h @@ -30,6 +30,8 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate; class LINPHONE_PUBLIC ClientGroupChatRoom : public ChatRoom, public RemoteConference { + friend class ClientGroupToBasicChatRoomPrivate; + public: // TODO: Make me private. ClientGroupChatRoom ( diff --git a/src/chat/chat-room/client-group-to-basic-chat-room.cpp b/src/chat/chat-room/client-group-to-basic-chat-room.cpp index 3cf1783a6..e726cc362 100644 --- a/src/chat/chat-room/client-group-to-basic-chat-room.cpp +++ b/src/chat/chat-room/client-group-to-basic-chat-room.cpp @@ -17,8 +17,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "client-group-chat-room-p.h" #include "client-group-to-basic-chat-room.h" #include "proxy-chat-room-p.h" +#include "c-wrapper/c-wrapper.h" +#include "core/core-p.h" // ============================================================================= @@ -30,15 +33,50 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupToBasicChatRoomPrivate : public ProxyChatRoomPrivate { public: - inline void sendChatMessage (const shared_ptr &chatMessage) override { - ProxyChatRoomPrivate::sendChatMessage(chatMessage); - // TODO: Try migration. + void onChatRoomInsertRequested (const shared_ptr &chatRoom) override { + L_Q(); + // Insert the proxy chat room instead of the real one + q->getCore()->getPrivate()->insertChatRoom(q->getSharedFromThis()); } - inline void onChatMessageReceived (const shared_ptr &chatMessage) override { - ProxyChatRoomPrivate::onChatMessageReceived(chatMessage); - // TODO: Try migration. + void onChatRoomInsertInDatabaseRequested (const shared_ptr &chatRoom) override { + L_Q(); + // Insert the proxy chat room instead of the real one + q->getCore()->getPrivate()->insertChatRoomWithDb(q->getSharedFromThis()); } + + void onCallSessionSetReleased (const std::shared_ptr &session) override { + if (!(chatRoom->getCapabilities() & static_cast(ChatRoom::Capabilities::Conference))) + return; + static_pointer_cast(chatRoom)->getPrivate()->onCallSessionSetReleased(session); + } + + void onCallSessionStateChanged ( + const shared_ptr &session, + LinphoneCallState newState, + const string &message + ) override { + L_Q(); + shared_ptr cgcr = dynamic_pointer_cast(chatRoom); + if (!cgcr) + return; + if ((newState == LinphoneCallError) && (cgcr->getState() == ChatRoom::State::CreationPending) + && (invitedAddresses.size() == 1)) { + cgcr->getPrivate()->setCallSessionListener(cgcr->getPrivate()); + cgcr->getPrivate()->setChatRoomListener(cgcr->getPrivate()); + cgcr->getPrivate()->setState(ChatRoom::State::CreationFailed); + Core::deleteChatRoom(q->getSharedFromThis()); + LinphoneChatRoom *lcr = L_GET_C_BACK_PTR(q); + L_SET_CPP_PTR_FROM_C_OBJECT(lcr, cgcr->getCore()->getOrCreateBasicChatRoom(invitedAddresses.front())); + return; + } + cgcr->getPrivate()->onCallSessionStateChanged(session, newState, message); + } + +private: + list invitedAddresses; + + L_DECLARE_PUBLIC(ClientGroupToBasicChatRoom); }; // ============================================================================= @@ -46,4 +84,27 @@ public: ClientGroupToBasicChatRoom::ClientGroupToBasicChatRoom (const shared_ptr &chatRoom) : ProxyChatRoom(*new ClientGroupToBasicChatRoomPrivate, chatRoom) {} +void ClientGroupToBasicChatRoom::addParticipant ( + const IdentityAddress &participantAddress, + const CallSessionParams *params, + bool hasMedia +) { + L_D(); + if (getState() == ChatRoom::State::Instantiated) { + d->invitedAddresses.clear(); + d->invitedAddresses.push_back(participantAddress); + } + ProxyChatRoom::addParticipant(participantAddress, params, hasMedia); +} +void ClientGroupToBasicChatRoom::addParticipants ( + const std::list &addresses, + const CallSessionParams *params, + bool hasMedia +) { + L_D(); + if ((getState() == ChatRoom::State::Instantiated) && (addresses.size() == 1)) + d->invitedAddresses = addresses; + ProxyChatRoom::addParticipants(addresses, params, hasMedia); +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/client-group-to-basic-chat-room.h b/src/chat/chat-room/client-group-to-basic-chat-room.h index 6e5cc1173..94180ecdf 100644 --- a/src/chat/chat-room/client-group-to-basic-chat-room.h +++ b/src/chat/chat-room/client-group-to-basic-chat-room.h @@ -32,6 +32,17 @@ class LINPHONE_PUBLIC ClientGroupToBasicChatRoom : public ProxyChatRoom { public: ClientGroupToBasicChatRoom (const std::shared_ptr &chatRoom); + void addParticipant ( + const IdentityAddress &participantAddress, + const CallSessionParams *params, + bool hasMedia + ) override; + void addParticipants ( + const std::list &addresses, + const CallSessionParams *params, + bool hasMedia + ) override; + private: L_DECLARE_PRIVATE(ClientGroupToBasicChatRoom); L_DISABLE_COPY(ClientGroupToBasicChatRoom); diff --git a/src/chat/chat-room/proxy-chat-room.cpp b/src/chat/chat-room/proxy-chat-room.cpp index bb6bba60f..19cfd0770 100644 --- a/src/chat/chat-room/proxy-chat-room.cpp +++ b/src/chat/chat-room/proxy-chat-room.cpp @@ -65,11 +65,22 @@ time_t ProxyChatRoom::getLastUpdateTime () const { } // ----------------------------------------------------------------------------- - ProxyChatRoom::State ProxyChatRoom::getState () const { + +ProxyChatRoom::CapabilitiesMask ProxyChatRoom::getCapabilities () const { + L_D(); + return d->chatRoom->getCapabilities() | static_cast(ProxyChatRoom::Capabilities::Proxy); +} + +ProxyChatRoom::State ProxyChatRoom::getState () const { L_D(); return d->chatRoom->getState(); } +bool ProxyChatRoom::hasBeenLeft () const { + L_D(); + return d->chatRoom->hasBeenLeft(); +} + // ----------------------------------------------------------------------------- list> ProxyChatRoom::getHistory (int nLast) const { @@ -252,4 +263,11 @@ void ProxyChatRoom::leave () { d->chatRoom->leave(); } +// ----------------------------------------------------------------------------- + +const shared_ptr &ProxyChatRoom::getProxiedChatRoom () const { + L_D(); + return d->chatRoom; +} + LINPHONE_END_NAMESPACE diff --git a/src/chat/chat-room/proxy-chat-room.h b/src/chat/chat-room/proxy-chat-room.h index e78c40fe4..368dbf9ff 100644 --- a/src/chat/chat-room/proxy-chat-room.h +++ b/src/chat/chat-room/proxy-chat-room.h @@ -39,7 +39,9 @@ public: time_t getCreationTime () const override; time_t getLastUpdateTime () const override; + CapabilitiesMask getCapabilities () const override; State getState () const override; + bool hasBeenLeft () const override; std::list> getHistory (int nLast) const override; std::list> getHistoryRange (int begin, int end) const override; @@ -102,6 +104,8 @@ public: void join () override; void leave () override; + const std::shared_ptr &getProxiedChatRoom () const; + protected: ProxyChatRoom (ProxyChatRoomPrivate &p, const std::shared_ptr &chatRoom); diff --git a/src/chat/chat-room/server-group-chat-room-p.h b/src/chat/chat-room/server-group-chat-room-p.h index 8b12de422..ec3ac2bd2 100644 --- a/src/chat/chat-room/server-group-chat-room-p.h +++ b/src/chat/chat-room/server-group-chat-room-p.h @@ -21,14 +21,13 @@ #define _SERVER_GROUP_CHAT_ROOM_P_H_ #include "chat-room-p.h" -#include "conference/session/call-session-listener.h" #include "server-group-chat-room.h" // ============================================================================= LINPHONE_BEGIN_NAMESPACE -class ServerGroupChatRoomPrivate : public ChatRoomPrivate, public CallSessionListener { +class ServerGroupChatRoomPrivate : public ChatRoomPrivate { public: std::shared_ptr addParticipant (const IdentityAddress &participantAddress); void removeParticipant (const std::shared_ptr &participant); @@ -55,6 +54,11 @@ private: void finalizeCreation (); bool isAdminLeft () const; + // ChatRoomListener + void onChatRoomInsertRequested (const std::shared_ptr &chatRoom) override; + void onChatRoomInsertInDatabaseRequested (const std::shared_ptr &chatRoom) override; + void onChatRoomDeleteRequested (const std::shared_ptr &chatRoom) override; + // CallSessionListener void onCallSessionStateChanged ( const std::shared_ptr &session, @@ -63,6 +67,7 @@ private: ) override; std::list> removedParticipants; + ChatRoomListener *chatRoomListener = this; L_DECLARE_PUBLIC(ServerGroupChatRoom); }; diff --git a/src/core/core.h b/src/core/core.h index c3ceb823f..74edc1d2a 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -46,6 +46,8 @@ class LINPHONE_PUBLIC Core : public Object { friend class ChatRoom; friend class ChatRoomPrivate; friend class ClientGroupChatRoom; + friend class ClientGroupChatRoomPrivate; + friend class ClientGroupToBasicChatRoomPrivate; friend class LocalConferenceEventHandlerPrivate; friend class MainDb; friend class MainDbChatMessageKey; diff --git a/tester/group_chat_tester.c b/tester/group_chat_tester.c index cb14e6b57..013a87744 100644 --- a/tester/group_chat_tester.c +++ b/tester/group_chat_tester.c @@ -121,6 +121,7 @@ static void configure_core_for_conference (LinphoneCore *core, const char* usern linphone_core_set_conference_factory_uri(core, factoryUri); bctbx_free(factoryUri); linphone_config_set_int(linphone_core_get_config(core), "sip", "use_cpim", 1); + linphone_core_set_linphone_specs(core, "groupchat"); } static void _configure_core_for_conference (LinphoneCoreManager *lcm, LinphoneAddress *factoryAddr) { @@ -1339,6 +1340,46 @@ static void multiple_is_composing_notification(void) { linphone_core_manager_destroy(laure); } +static void group_chat_room_fallback_to_basic_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; + int dummy = 0; + coresManagerList = bctbx_list_append(coresManagerList, marie); + coresManagerList = bctbx_list_append(coresManagerList, pauline); + bctbx_list_t *coresList = init_core_for_conference(coresManagerList); + linphone_core_set_linphone_specs(pauline->lc, NULL); + start_core_for_conference(coresManagerList); + participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc))); + stats initialMarieStats = marie->stat; + + // Marie creates a new group chat room + LinphoneChatRoom *chatRoom = linphone_core_create_client_group_chat_room(marie->lc, "Fallback"); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateInstantiated, initialMarieStats.number_of_LinphoneChatRoomStateInstantiated + 1, 100)); + + // Add participants + linphone_chat_room_add_participants(chatRoom, participantsAddresses); + + // Check that the group chat room creation fails and that a fallback to a basic chat room is done + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateCreationPending, initialMarieStats.number_of_LinphoneChatRoomStateCreationPending + 1, 10000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateCreationFailed, initialMarieStats.number_of_LinphoneChatRoomStateCreationFailed + 1, 10000)); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateCreated, initialMarieStats.number_of_LinphoneChatRoomStateCreated + 1, 10000)); + BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(chatRoom), 1, int, "%d"); + BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(chatRoom) & LinphoneChatRoomCapabilitiesBasic); + bctbx_list_free_with_data(participantsAddresses, (bctbx_list_free_func)linphone_address_unref); + participantsAddresses = NULL; + + // Clean db from chat room + linphone_core_delete_chat_room(marie->lc, chatRoom); + + wait_for_list(coresList, &dummy, 1, 1000); + 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"), @@ -1355,7 +1396,9 @@ test_t group_chat_tests[] = { TEST_TWO_TAGS("Reinvited after removed from group chat room", group_chat_room_reinvited_after_removed, "Server", "LeaksMemory"), TEST_TWO_TAGS("Notify after disconnection", group_chat_room_notify_after_disconnection, "Server", "LeaksMemory"), TEST_TWO_TAGS("Send refer to all participants devices", group_chat_room_send_refer_to_all_devices, "Server", "LeaksMemory"), - TEST_TWO_TAGS("Send multiple is composing", multiple_is_composing_notification, "Server", "LeaksMemory") + TEST_TWO_TAGS("Send multiple is composing", multiple_is_composing_notification, "Server", "LeaksMemory"), + TEST_TWO_TAGS("Create chat room with incompatible friend", group_chat_room_create_room_with_incompatible_friend, "Server", "LeaksMemory"), + TEST_TWO_TAGS("Fallback to basic chat room", group_chat_room_fallback_to_basic_chat_room, "Server", "LeaksMemory") }; test_suite_t group_chat_test_suite = { diff --git a/tester/rcfiles/chloe_rc b/tester/rcfiles/chloe_rc index fb5c76a90..6fdd750f4 100644 --- a/tester/rcfiles/chloe_rc +++ b/tester/rcfiles/chloe_rc @@ -4,7 +4,6 @@ sip_tcp_port=-1 sip_tls_port=-1 default_proxy=0 ping_with_options=0 - composing_idle_timeout=1 [auth_info_0] diff --git a/tester/rcfiles/laure_tcp_rc b/tester/rcfiles/laure_tcp_rc index e39a83e49..6f19d7a5c 100644 --- a/tester/rcfiles/laure_tcp_rc +++ b/tester/rcfiles/laure_tcp_rc @@ -5,7 +5,6 @@ sip_tls_port=5093 default_proxy=0 ping_with_options=0 - [auth_info_0] username=laure userid=laure diff --git a/tester/rcfiles/pauline_rc b/tester/rcfiles/pauline_rc index c5f1fed4d..44bb1b6d5 100644 --- a/tester/rcfiles/pauline_rc +++ b/tester/rcfiles/pauline_rc @@ -4,7 +4,6 @@ sip_tcp_port=-1 sip_tls_port=-1 default_proxy=0 ping_with_options=0 - composing_idle_timeout=1 [auth_info_0]