diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9b49492b4..78b2c35cc 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -721,10 +721,25 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){ LinphonePrivate::Address addr(sal_address_as_string(refer_to)); if (addr.isValid()) { LinphoneCore *lc = reinterpret_cast(op->get_sal()->get_user_pointer()); - if (addr.hasParam("admin")) { + if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) { + // The server asks a participant to leave a chat room + LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, addr.asStringUriOnly().c_str()); + if (cr) { + L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave(); + static_cast(op)->reply(SalReasonNone); + return; + } + static_cast(op)->reply(SalReasonDeclined); + } else if (addr.hasParam("admin")) { LinphoneChatRoom *cr = _linphone_core_find_group_chat_room(lc, op->get_to()); if (cr) { - std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(addr); + Address fromAddr(op->get_from()); + std::shared_ptr participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(fromAddr); + if (!participant || !participant->isAdmin()) { + static_cast(op)->reply(SalReasonDeclined); + return; + } + participant = L_GET_CPP_PTR_FROM_C_OBJECT(cr)->findParticipant(addr); if (participant) { bool value = Utils::stob(addr.getParamValue("admin")); L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setParticipantAdminStatus(participant, value); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index cfdb0e84e..143dc746d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -7105,15 +7105,32 @@ bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id } void _linphone_core_add_group_chat_room(LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr) { - Address cleanedAddr = addr; + Address cleanedAddr(addr); + cleanedAddr.clean(); cleanedAddr.setPort(0); bctbx_pair_t *pair = reinterpret_cast(bctbx_pair_cchar_new(cleanedAddr.asStringUriOnly().c_str(), linphone_chat_room_ref(cr))); bctbx_map_cchar_insert_and_delete(lc->group_chat_rooms, pair); } +void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr) { + const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(cr); + Address cleanedAddr(*L_GET_CPP_PTR_FROM_C_OBJECT(confAddr)); + cleanedAddr.clean(); + cleanedAddr.setPort(0); + bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); + bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); + if (!bctbx_iterator_cchar_equals(it, endit)) { + bctbx_map_cchar_erase(lc->group_chat_rooms, it); + linphone_chat_room_unref(cr); + } + bctbx_iterator_cchar_delete(endit); + bctbx_iterator_cchar_delete(it); +} + LinphoneChatRoom *_linphone_core_find_group_chat_room(const LinphoneCore *lc, const char *id) { LinphoneChatRoom *result = nullptr; Address cleanedAddr(id); + cleanedAddr.clean(); cleanedAddr.setPort(0); bctbx_iterator_t *it = bctbx_map_cchar_find_key(lc->group_chat_rooms, cleanedAddr.asStringUriOnly().c_str()); bctbx_iterator_t *endit = bctbx_map_cchar_end(lc->group_chat_rooms); diff --git a/coreapi/private.h b/coreapi/private.h index ca1d8cf20..9e8c32bb0 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -449,8 +449,9 @@ bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription extern LinphonePrivate::Sal::Callbacks linphone_sal_callbacks; LINPHONE_PUBLIC bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LINPHONE_PUBLIC bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); -bool_t _linphone_core_has_group_chat_room(const LinphoneCore *lc, const char *id); -void _linphone_core_add_group_chat_room(LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr); +bool_t _linphone_core_has_group_chat_room (const LinphoneCore *lc, const char *id); +void _linphone_core_add_group_chat_room (LinphoneCore *lc, const LinphonePrivate::Address &addr, LinphoneChatRoom *cr); +void _linphone_core_remove_group_chat_room(LinphoneCore *lc, LinphoneChatRoom *cr); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index ce02a4563..fb7270231 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -150,11 +150,22 @@ void ClientGroupChatRoom::leave () { } void ClientGroupChatRoom::removeParticipant (const shared_ptr &participant) { - // TODO + L_D(); + SalReferOp *referOp = new SalReferOp(d->core->sal); + LinphoneAddress *lAddr = linphone_address_new(conferenceAddress.asString().c_str()); + linphone_configure_op(d->core, referOp, lAddr, nullptr, false); + linphone_address_unref(lAddr); + Address referToAddr = participant->getAddress(); + referToAddr.setParam("text"); + referToAddr.setUriParam("method", "BYE"); + referToAddr.setDomain(""); + referToAddr.setPort(-1); + referOp->send_refer(referToAddr.getPrivate()->getInternalAddress()); + referOp->unref(); } void ClientGroupChatRoom::removeParticipants (const list> &participants) { - // TODO + RemoteConference::removeParticipants(participants); } void ClientGroupChatRoom::setParticipantAdminStatus (shared_ptr &participant, bool isAdmin) { @@ -231,7 +242,7 @@ void ClientGroupChatRoom::onParticipantAdded (const Address &addr) { void ClientGroupChatRoom::onParticipantRemoved (const Address &addr) { shared_ptr participant = findParticipant(addr); if (!participant) { - lWarning() << "Participant " << participant << " removed but is not in the list of participants!"; + lWarning() << "Participant " << addr.asString() << " removed but not in the list of participants!"; return; } LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this); @@ -315,9 +326,8 @@ void ClientGroupChatRoom::onCallSessionStateChanged (const std::shared_ptrgetPrivate()->getSession()->terminate(); } } else { - if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) { + if ((state == LinphoneCallReleased) && (d->state == ChatRoom::State::TerminationPending)) onConferenceTerminated(conferenceAddress); - } } }