Handle incoming INVITE from conference server to create ClientGroupChatRoom.

This commit is contained in:
Ghislain MARY 2018-03-16 14:45:54 +01:00
parent d1a68a0e5c
commit 5fb8f9686a
38 changed files with 365 additions and 174 deletions

View file

@ -41,6 +41,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "call/call-p.h"
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-room/chat-room.h"
#include "chat/chat-room/client-group-chat-room-p.h"
#include "chat/chat-room/server-group-chat-room-p.h"
#include "conference/participant.h"
#include "conference/session/call-session-p.h"
@ -56,8 +57,14 @@ using namespace LinphonePrivate;
static void register_failure(SalOp *op);
static void call_received(SalCallOp *h) {
/* Look if this INVITE is for a call that has already been notified but broken because of network failure */
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(h->get_sal()->get_user_pointer());
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
h->decline(SalReasonServiceUnavailable, nullptr);
return;
}
/* Look if this INVITE is for a call that has already been notified but broken because of network failure */
if (L_GET_PRIVATE_FROM_C_OBJECT(lc)->inviteReplacesABrokenCall(h))
return;
@ -107,16 +114,28 @@ static void call_received(SalCallOp *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(
ChatRoomId(IdentityAddress(h->get_to()), IdentityAddress(h->get_to()))
);
if (chatRoom) {
L_GET_PRIVATE(static_pointer_cast<ServerGroupChatRoom>(chatRoom))->confirmJoining(h);
linphone_address_unref(toAddr);
linphone_address_unref(fromAddr);
linphone_address_unref(toAddr);
linphone_address_unref(fromAddr);
if (linphone_core_conference_server_enabled(lc)) {
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
ChatRoomId(IdentityAddress(h->get_to()), IdentityAddress(h->get_to()))
);
if (chatRoom) {
L_GET_PRIVATE(static_pointer_cast<ServerGroupChatRoom>(chatRoom))->confirmJoining(h);
} else {
//invite is for an unknown chatroom
h->decline(SalReasonNotFound, nullptr);
}
} else {
//invite is for an unknown chatroom
h->decline(SalReasonNotFound, nullptr);
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
ChatRoomId(IdentityAddress(h->get_from()), IdentityAddress(h->get_to()))
);
if (!chatRoom) {
chatRoom = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createClientGroupChatRoom(
L_C_TO_STRING(h->get_subject()), h->get_remote_contact(), h->get_remote_body(), false
);
}
L_GET_PRIVATE(static_pointer_cast<ClientGroupChatRoom>(chatRoom))->confirmJoining(h);
}
return;
} else {
@ -201,7 +220,8 @@ static void call_rejected(SalCallOp *h){
static void call_ringing(SalOp *h) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(h->get_user_pointer());
if (!session) return;
L_GET_PRIVATE(session)->remoteRinging();
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->remoteRinging();
}
/*
@ -215,7 +235,8 @@ static void call_accepted(SalOp *op) {
ms_warning("call_accepted: CallSession no longer exists");
return;
}
L_GET_PRIVATE(session)->accepted();
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->accepted();
}
/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
@ -225,7 +246,8 @@ static void call_updating(SalOp *op, bool_t is_update) {
ms_warning("call_updating: CallSession no longer exists");
return;
}
L_GET_PRIVATE(session)->updating(!!is_update);
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->updating(!!is_update);
}
@ -235,7 +257,8 @@ static void call_ack_received(SalOp *op, SalCustomHeader *ack) {
ms_warning("call_ack_received(): no CallSession for which an ack is expected");
return;
}
L_GET_PRIVATE(session)->ackReceived(reinterpret_cast<LinphoneHeaders *>(ack));
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->ackReceived(reinterpret_cast<LinphoneHeaders *>(ack));
}
@ -245,25 +268,26 @@ static void call_ack_being_sent(SalOp *op, SalCustomHeader *ack) {
ms_warning("call_ack_being_sent(): no CallSession for which an ack is supposed to be sent");
return;
}
L_GET_PRIVATE(session)->ackBeingSent(reinterpret_cast<LinphoneHeaders *>(ack));
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->ackBeingSent(reinterpret_cast<LinphoneHeaders *>(ack));
}
static void call_terminated(SalOp *op, const char *from) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
if (!session)
return;
L_GET_PRIVATE(session)->terminated();
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->terminated();
}
static void call_failure(SalOp *op) {
shared_ptr<LinphonePrivate::CallSession> session;
if (op->get_user_pointer())
session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer())->getSharedFromThis();
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
if (!session) {
ms_warning("Failure reported on already terminated CallSession");
return;
}
L_GET_PRIVATE(session)->failure();
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->failure();
}
static void call_released(SalOp *op) {
@ -273,7 +297,8 @@ static void call_released(SalOp *op) {
* when declining an incoming call with busy because maximum number of calls is reached. */
return;
}
L_GET_PRIVATE(session)->setState(LinphonePrivate::CallSession::State::Released, "Call released");
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->setState(LinphonePrivate::CallSession::State::Released, "Call released");
}
static void call_cancel_done(SalOp *op) {
@ -282,7 +307,8 @@ static void call_cancel_done(SalOp *op) {
ms_warning("Cancel done reported on already terminated CallSession");
return;
}
L_GET_PRIVATE(session)->cancelDone();
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->cancelDone();
}
static void auth_failure(SalOp *op, SalAuthInfo* info) {
@ -344,24 +370,26 @@ static void vfu_request(SalOp *op) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
if (!session)
return;
LinphonePrivate::MediaSession *mediaSession = dynamic_cast<LinphonePrivate::MediaSession *>(session);
if (!mediaSession) {
auto sessionRef = session->getSharedFromThis();
auto mediaSessionRef = dynamic_pointer_cast<LinphonePrivate::MediaSession>(sessionRef);
if (!mediaSessionRef) {
ms_warning("VFU request but no MediaSession!");
return;
}
L_GET_PRIVATE(mediaSession)->sendVfu();
L_GET_PRIVATE(mediaSessionRef)->sendVfu();
}
static void dtmf_received(SalOp *op, char dtmf) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
if (!session)
return;
LinphonePrivate::MediaSession *mediaSession = dynamic_cast<LinphonePrivate::MediaSession *>(session);
if (!mediaSession) {
auto sessionRef = session->getSharedFromThis();
auto mediaSessionRef = dynamic_pointer_cast<LinphonePrivate::MediaSession>(sessionRef);
if (!mediaSessionRef) {
ms_warning("DTMF received but no MediaSession!");
return;
}
L_GET_PRIVATE(mediaSession)->dtmfReceived(dtmf);
L_GET_PRIVATE(mediaSessionRef)->dtmfReceived(dtmf);
}
static void call_refer_received(SalOp *op, const SalAddress *referTo) {
@ -372,7 +400,8 @@ static void call_refer_received(SalOp *op, const SalAddress *referTo) {
if (referToAddr.isValid())
method = referToAddr.getMethodParam();
if (session && (method.empty() || (method == "INVITE"))) {
L_GET_PRIVATE(session)->referred(referToAddr);
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->referred(referToAddr);
} else {
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(op->get_sal()->get_user_pointer());
linphone_core_notify_refer_received(lc, addrStr);
@ -382,6 +411,12 @@ static void call_refer_received(SalOp *op, const SalAddress *referTo) {
static void message_received(SalOp *op, const SalMessage *msg){
LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer();
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
static_cast<SalMessageOp *>(op)->reply(SalReasonServiceUnavailable);
return;
}
LinphoneCall *call=(LinphoneCall*)op->get_user_pointer();
LinphoneReason reason = lc->chat_deny_code;
if (reason == LinphoneReasonNone) {
@ -414,6 +449,10 @@ static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *
static void subscribe_presence_received(SalPresenceOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer();
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
op->decline(SalReasonServiceUnavailable);
return;
}
linphone_subscription_new(lc,op,from);
}
@ -428,7 +467,8 @@ static void ping_reply(SalOp *op) {
ms_warning("Ping reply without CallSession attached...");
return;
}
L_GET_PRIVATE(session)->pingReply();
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->pingReply();
}
static bool_t fill_auth_info_with_client_certificate(LinphoneCore *lc, SalAuthInfo* sai) {
@ -531,6 +571,7 @@ static void notify_refer(SalOp *op, SalReferStatus status) {
ms_warning("Receiving notify_refer for unknown CallSession");
return;
}
auto sessionRef = session->getSharedFromThis();
LinphonePrivate::CallSession::State cstate;
switch (status) {
case SalReferTrying:
@ -544,9 +585,9 @@ static void notify_refer(SalOp *op, SalReferStatus status) {
cstate = LinphonePrivate::CallSession::State::Error;
break;
}
L_GET_PRIVATE(session)->setTransferState(cstate);
L_GET_PRIVATE(sessionRef)->setTransferState(cstate);
if (cstate == LinphonePrivate::CallSession::State::Connected)
session->terminate(); // Automatically terminate the call as the transfer is complete
sessionRef->terminate(); // Automatically terminate the call as the transfer is complete
}
static LinphoneChatMessageState chatStatusSal2Linphone(SalMessageDeliveryStatus status){
@ -575,7 +616,8 @@ static void info_received(SalOp *op, SalBodyHandler *body_handler) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
if (!session)
return;
L_GET_PRIVATE(session)->infoReceived(body_handler);
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->infoReceived(body_handler);
}
static void subscribe_response(SalOp *op, SalSubscribeStatus status, int will_retry){
@ -622,6 +664,11 @@ static void subscribe_received(SalSubscribeOp *op, const char *eventname, const
LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer();
LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer();
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
op->decline(SalReasonServiceUnavailable);
return;
}
if (lev==NULL) {
lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionIncoming,eventname);
linphone_event_set_state(lev,LinphoneSubscriptionIncomingReceived);
@ -700,6 +747,12 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){
bctbx_free(refer_uri);
if (addr.isValid()) {
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(op->get_sal()->get_user_pointer());
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
static_cast<SalReferOp *>(op)->reply(SalReasonDeclined);
return;
}
if (addr.hasUriParam("method") && (addr.getUriParamValue("method") == "BYE")) {
if (linphone_core_conference_server_enabled(lc)) {
// Removal of a participant at the server side
@ -754,7 +807,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){
ChatRoomId(addr, IdentityAddress(op->get_to()))
);
if (!chatRoom)
chatRoom = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createClientGroupChatRoom("", addr.asString(), false);
chatRoom = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createClientGroupChatRoom("", addr.asString(), Content(), false);
chatRoom->join();
static_cast<SalReferOp *>(op)->reply(SalReasonNone);
return;

View file

@ -919,8 +919,11 @@ void linphone_core_report_call_log(LinphoneCore *lc, LinphoneCallLog *call_log){
}
linphone_address_unref(conference_factory_addr);
}
const char *username = linphone_address_get_username(call_log->to);
if (username && (strstr(username, "chatroom-") == username))
const char *usernameFrom = linphone_address_get_username(call_log->from);
const char *usernameTo = linphone_address_get_username(call_log->to);
if ((usernameFrom && (strstr(usernameFrom, "chatroom-") == usernameFrom))
|| (usernameTo && (strstr(usernameTo, "chatroom-") == usernameTo))
)
return;
// End of workaround

View file

@ -288,6 +288,7 @@ void _linphone_chat_room_notify_participant_device_removed(LinphoneChatRoom *cr,
void _linphone_chat_room_notify_participant_admin_status_changed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_state_changed(LinphoneChatRoom *cr, LinphoneChatRoomState newState);
void _linphone_chat_room_notify_subject_changed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_all_information_received(LinphoneChatRoom *cr);
void _linphone_chat_room_notify_undecryptable_message_received(LinphoneChatRoom *cr, LinphoneChatMessage *msg);
void _linphone_chat_room_notify_chat_message_received(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_chat_message_sent(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);

View file

@ -235,6 +235,12 @@ typedef void (*LinphoneChatRoomCbsParticipantDeviceAddedCb) (LinphoneChatRoom *c
*/
typedef void (*LinphoneChatRoomCbsParticipantDeviceRemovedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
/**
* Callback used to notify a chat room has received all its information.
* @param[in] cr #LinphoneChatRoom object
*/
typedef void (*LinphoneChatRoomCbsAllInformationReceivedCb) (LinphoneChatRoom *cr);
/**
* Callback used when a group chat room is created server-side to generate the address of the chat room.
* The function linphone_chat_room_set_conference_address() needs to be called by this callback.

View file

@ -229,6 +229,20 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantDeviceRemovedCb linphone_chat_room
*/
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participant_device_removed (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantDeviceRemovedCb cb);
/**
* Get the all information received callback.
* @param[in] cbs LinphoneChatRoomCbs object.
* @return The current all information received callback.
*/
LINPHONE_PUBLIC LinphoneChatRoomCbsAllInformationReceivedCb linphone_chat_room_cbs_get_all_information_received (const LinphoneChatRoomCbs *cbs);
/**
* Set the all information received callback.
* @param[in] cbs LinphoneChatRoomCbs object.
* @param[in] cb The all information received callback to be used.
*/
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_all_information_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsAllInformationReceivedCb cb);
/**
* Get the conference address generation callback.
* @param[in] cbs LinphoneChatRoomCbs object

View file

@ -35,6 +35,7 @@ struct _LinphoneChatRoomCbs {
LinphoneChatRoomCbsParticipantAdminStatusChangedCb participantAdminStatusChangedCb;
LinphoneChatRoomCbsStateChangedCb stateChangedCb;
LinphoneChatRoomCbsSubjectChangedCb subjectChangedCb;
LinphoneChatRoomCbsAllInformationReceivedCb allInformationReceivedCb;
LinphoneChatRoomCbsUndecryptableMessageReceivedCb undecryptableMessageReceivedCb;
LinphoneChatRoomCbsChatMessageReceivedCb chatMessageReceivedCb;
LinphoneChatRoomCbsChatMessageSentCb chatMessageSentCb;
@ -176,6 +177,14 @@ void linphone_chat_room_cbs_set_participant_device_removed (LinphoneChatRoomCbs
cbs->participantDeviceRemovedCb = cb;
}
LinphoneChatRoomCbsAllInformationReceivedCb linphone_chat_room_cbs_get_all_information_received (const LinphoneChatRoomCbs *cbs) {
return cbs->allInformationReceivedCb;
}
void linphone_chat_room_cbs_set_all_information_received (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsAllInformationReceivedCb cb) {
cbs->allInformationReceivedCb = cb;
}
LinphoneChatRoomCbsConferenceAddressGenerationCb linphone_chat_room_cbs_get_conference_address_generation (const LinphoneChatRoomCbs *cbs) {
return cbs->conferenceAddressGenerationCb;
}

View file

@ -480,6 +480,10 @@ void _linphone_chat_room_notify_subject_changed(LinphoneChatRoom *cr, const Linp
NOTIFY_IF_EXIST(SubjectChanged, subject_changed, cr, event_log)
}
void _linphone_chat_room_notify_all_information_received(LinphoneChatRoom *cr) {
NOTIFY_IF_EXIST(AllInformationReceived, all_information_received, cr)
}
void _linphone_chat_room_notify_undecryptable_message_received(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
NOTIFY_IF_EXIST(UndecryptableMessageReceived, undecryptable_message_received, cr, msg)
}

View file

@ -88,7 +88,7 @@ void BasicChatRoom::addParticipants (const list<IdentityAddress> &, const CallSe
lError() << "addParticipants() is not allowed on a BasicChatRoom";
}
void BasicChatRoom::removeParticipant (const shared_ptr<const Participant> &) {
void BasicChatRoom::removeParticipant (const shared_ptr<Participant> &) {
lError() << "removeParticipant() is not allowed on a BasicChatRoom";
}

View file

@ -48,7 +48,7 @@ public:
void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override;
void addParticipants (const std::list<IdentityAddress> &addresses, const CallSessionParams *params, bool hasMedia) override;
void removeParticipant (const std::shared_ptr<const Participant> &participant) override;
void removeParticipant (const std::shared_ptr<Participant> &participant) override;
void removeParticipants (const std::list<std::shared_ptr<Participant>> &participants) override;
std::shared_ptr<Participant> findParticipant (const IdentityAddress &addr) const override;

View file

@ -78,7 +78,7 @@ public:
}
migrationRealTime = currentRealTime;
clientGroupChatRoom = static_pointer_cast<ClientGroupChatRoom>(
chatRoom->getCore()->getPrivate()->createClientGroupChatRoom(chatRoom->getSubject(), "", false)
chatRoom->getCore()->getPrivate()->createClientGroupChatRoom(chatRoom->getSubject(), "", Content(), false)
);
clientGroupChatRoom->getPrivate()->setCallSessionListener(this);
clientGroupChatRoom->getPrivate()->setChatRoomListener(this);

View file

@ -35,6 +35,7 @@ public:
void notifyReceived (const std::string &body);
void multipartNotifyReceived (const std::string &body);
void confirmJoining (SalCallOp *op);
void setCallSessionListener (CallSessionListener *listener);
void setChatRoomListener (ChatRoomListener *listener) { chatRoomListener = listener; }
@ -47,12 +48,16 @@ public:
void onCallSessionSetReleased (const std::shared_ptr<CallSession> &session) override;
void onCallSessionStateChanged (const std::shared_ptr<CallSession> &session, CallSession::State state, const std::string &message) override;
void onChatRoomCreated (const Address &remoteContact);
private:
void acceptSession (const std::shared_ptr<CallSession> &session);
CallSessionListener *callSessionListener = this;
ChatRoomListener *chatRoomListener = this;
ClientGroupChatRoom::CapabilitiesMask capabilities = ClientGroupChatRoom::Capabilities::Conference;
bool deletionOnTerminationEnabled = false;
BackgroundTask bgTask;
BackgroundTask bgTask { "Subscribe/notify of full state conference" };
L_DECLARE_PUBLIC(ClientGroupChatRoom);
};

View file

@ -101,6 +101,31 @@ void ClientGroupChatRoomPrivate::setCallSessionListener (CallSessionListener *li
}
}
void ClientGroupChatRoomPrivate::confirmJoining (SalCallOp *op) {
L_Q();
L_Q_T(RemoteConference, qConference);
auto focus = qConference->getPrivate()->focus;
bool previousSession = (focus->getPrivate()->getSession() != nullptr);
auto session = focus->getPrivate()->createSession(*q, nullptr, false, this);
session->configure(LinphoneCallIncoming, nullptr, op, Address(op->get_from()), Address(op->get_to()));
session->startIncomingNotification(false);
if (!previousSession) {
setState(ClientGroupChatRoom::State::CreationPending);
// Handle participants addition
list<IdentityAddress> identAddresses = ClientGroupChatRoom::parseResourceLists(op->get_remote_body());
for (const auto &addr : identAddresses) {
auto participant = q->findParticipant(addr);
if (!participant) {
participant = make_shared<Participant>(addr);
qConference->getPrivate()->participants.push_back(participant);
}
}
}
acceptSession(session);
}
// -----------------------------------------------------------------------------
void ClientGroupChatRoomPrivate::onChatRoomInsertRequested (const shared_ptr<AbstractChatRoom> &chatRoom) {
@ -139,14 +164,11 @@ void ClientGroupChatRoomPrivate::onCallSessionStateChanged (
if (newState == CallSession::State::Connected) {
if (q->getState() == ChatRoom::State::CreationPending) {
IdentityAddress addr(session->getRemoteContactAddress()->asStringUriOnly());
q->onConferenceCreated(addr);
if (session->getRemoteContactAddress()->hasParam("isfocus")) {
bgTask.start(q->getCore(), 32); // It will be stopped when receiving the first notify
qConference->getPrivate()->eventHandler->subscribe(q->getChatRoomId());
}
onChatRoomCreated(*session->getRemoteContactAddress());
} else if (q->getState() == ChatRoom::State::TerminationPending)
qConference->getPrivate()->focus->getPrivate()->getSession()->terminate();
} else if (newState == CallSession::State::End) {
q->onConferenceTerminated(q->getConferenceAddress());
} else if (newState == CallSession::State::Released) {
if (q->getState() == ChatRoom::State::TerminationPending) {
if (session->getReason() == LinphoneReasonNone) {
@ -174,23 +196,46 @@ void ClientGroupChatRoomPrivate::onCallSessionStateChanged (
}
}
void ClientGroupChatRoomPrivate::onChatRoomCreated (const Address &remoteContact) {
L_Q();
L_Q_T(RemoteConference, qConference);
IdentityAddress addr(remoteContact);
q->onConferenceCreated(addr);
if (remoteContact.hasParam("isfocus")) {
bgTask.start(q->getCore(), 32); // It will be stopped when receiving the first notify
qConference->getPrivate()->eventHandler->subscribe(q->getChatRoomId());
}
}
// -----------------------------------------------------------------------------
void ClientGroupChatRoomPrivate::acceptSession (const shared_ptr<CallSession> &session) {
if (session->getState() == CallSession::State::UpdatedByRemote)
session->acceptUpdate();
else
session->accept();
}
// =============================================================================
ClientGroupChatRoom::ClientGroupChatRoom (
const shared_ptr<Core> &core,
const string &uri,
const IdentityAddress &me,
const string &subject
const string &subject,
const Content &content
) : ChatRoom(*new ClientGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(), me)),
RemoteConference(core, me, nullptr) {
L_D_T(RemoteConference, dConference);
L_D();
IdentityAddress focusAddr(uri);
dConference->focus = make_shared<Participant>(focusAddr);
dConference->focus->getPrivate()->addDevice(focusAddr);
RemoteConference::setSubject(subject);
d->bgTask.setName("Subscribe/notify of full state conference");
list<IdentityAddress> identAddresses = Conference::parseResourceLists(content);
for (const auto &addr : identAddresses)
dConference->participants.push_back(make_shared<Participant>(addr));
}
ClientGroupChatRoom::ClientGroupChatRoom (
@ -251,7 +296,7 @@ ClientGroupChatRoom::CapabilitiesMask ClientGroupChatRoom::getCapabilities () co
}
bool ClientGroupChatRoom::hasBeenLeft () const {
return getState() != State::Created;
return (getState() != State::Created);
}
bool ClientGroupChatRoom::canHandleParticipants () const {
@ -328,7 +373,7 @@ void ClientGroupChatRoom::addParticipants (
}
}
void ClientGroupChatRoom::removeParticipant (const shared_ptr<const Participant> &participant) {
void ClientGroupChatRoom::removeParticipant (const shared_ptr<Participant> &participant) {
LinphoneCore *cCore = getCore()->getCCore();
SalReferOp *referOp = new SalReferOp(cCore->sal);
@ -422,7 +467,8 @@ void ClientGroupChatRoom::join () {
if (session) {
if (getState() != ChatRoom::State::TerminationPending)
session->startInvite(nullptr, "", nullptr);
d->setState(ChatRoom::State::CreationPending);
if (getState() != ChatRoom::State::Created)
d->setState(ChatRoom::State::CreationPending);
}
}
@ -454,6 +500,7 @@ void ClientGroupChatRoom::onConferenceCreated (const IdentityAddress &addr) {
dConference->focus->getPrivate()->addDevice(addr);
d->chatRoomId = ChatRoomId(addr, d->chatRoomId.getLocalAddress());
d->chatRoomListener->onChatRoomInsertRequested(getSharedFromThis());
d->setState(ChatRoom::State::Created);
}
void ClientGroupChatRoom::onConferenceKeywordsChanged (const vector<string> &keywords) {
@ -464,6 +511,7 @@ void ClientGroupChatRoom::onConferenceKeywordsChanged (const vector<string> &key
void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) {
L_D();
L_D_T(RemoteConference, dConference);
dConference->eventHandler->unsubscribe();
dConference->eventHandler->resetLastNotify();
d->setState(ChatRoom::State::Terminated);
d->addEvent(make_shared<ConferenceEvent>(
@ -479,21 +527,26 @@ void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) {
void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) {
L_D();
d->setState(ChatRoom::State::Created);
bool performMigration = false;
shared_ptr<AbstractChatRoom> chatRoom;
if (getParticipantCount() == 1) {
ChatRoomId id(getParticipants().front()->getAddress(), getMe()->getAddress());
shared_ptr<AbstractChatRoom> chatRoom = getCore()->findChatRoom(id);
if (chatRoom && (chatRoom->getCapabilities() & ChatRoom::Capabilities::Basic)) {
BasicToClientGroupChatRoom::migrate(getSharedFromThis(), chatRoom);
d->bgTask.stop();
return;
}
chatRoom = getCore()->findChatRoom(id);
if (chatRoom && (chatRoom->getCapabilities() & ChatRoom::Capabilities::Basic))
performMigration = true;
}
d->chatRoomListener->onChatRoomInsertInDatabaseRequested(getSharedFromThis());
if (performMigration)
BasicToClientGroupChatRoom::migrate(getSharedFromThis(), chatRoom);
else
d->chatRoomListener->onChatRoomInsertInDatabaseRequested(getSharedFromThis());
LinphoneChatRoom *cr = d->getCChatRoom();
_linphone_chat_room_notify_all_information_received(cr);
d->bgTask.stop();
// TODO: Bug. Event is inserted many times.
// Avoid this in the future. Deal with signals/slots system.
#if 0

View file

@ -43,7 +43,8 @@ public:
const std::shared_ptr<Core> &core,
const std::string &factoryUri,
const IdentityAddress &me,
const std::string &subject
const std::string &subject,
const Content &content
);
ClientGroupChatRoom (
@ -77,7 +78,7 @@ public:
void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override;
void addParticipants (const std::list<IdentityAddress> &addresses, const CallSessionParams *params, bool hasMedia) override;
void removeParticipant (const std::shared_ptr<const Participant> &participant) override;
void removeParticipant (const std::shared_ptr<Participant> &participant) override;
void removeParticipants (const std::list<std::shared_ptr<Participant>> &participants) override;
std::shared_ptr<Participant> findParticipant (const IdentityAddress &addr) const override;

View file

@ -248,7 +248,7 @@ void ProxyChatRoom::addParticipants (
return d->chatRoom->addParticipants(addresses, params, hasMedia);
}
void ProxyChatRoom::removeParticipant (const shared_ptr<const Participant> &participant) {
void ProxyChatRoom::removeParticipant (const shared_ptr<Participant> &participant) {
L_D();
d->chatRoom->removeParticipant(participant);
}

View file

@ -97,7 +97,7 @@ public:
bool hasMedia
) override;
void removeParticipant (const std::shared_ptr<const Participant> &participant) override;
void removeParticipant (const std::shared_ptr<Participant> &participant) override;
void removeParticipants (const std::list<std::shared_ptr<Participant>> &participants) override;
std::shared_ptr<Participant> findParticipant (const IdentityAddress &participantAddress) const override;

View file

@ -91,6 +91,7 @@ private:
static void copyMessageHeaders (const std::shared_ptr<Message> &fromMessage, const std::shared_ptr<ChatMessage> &toMessage);
void byeDevice (const std::shared_ptr<ParticipantDevice> &device);
void designateAdmin ();
void dispatchMessage (const std::shared_ptr<Message> &message, const std::string &uri);
void finalizeCreation ();
@ -100,7 +101,7 @@ private:
void queueMessage (const std::shared_ptr<Message> &msg, const IdentityAddress &deviceAddress);
void removeNonPresentParticipants (const std::list <IdentityAddress> &compatibleParticipants);
void onParticipantDeviceLeft (const std::shared_ptr<const CallSession> &session);
void onParticipantDeviceLeft (const std::shared_ptr<ParticipantDevice> &device);
// ChatRoomListener
void onChatRoomInsertRequested (const std::shared_ptr<AbstractChatRoom> &chatRoom) override;

View file

@ -92,6 +92,8 @@ LinphoneReason ServerGroupChatRoomPrivate::onSipMessageReceived (SalOp *, const
// -----------------------------------------------------------------------------
void ServerGroupChatRoomPrivate::byeDevice (const shared_ptr<ParticipantDevice> &device) {}
void ServerGroupChatRoomPrivate::designateAdmin () {}
void ServerGroupChatRoomPrivate::dispatchMessage (const shared_ptr<Message> &message, const string &uri) {}
@ -112,7 +114,7 @@ void ServerGroupChatRoomPrivate::removeNonPresentParticipants (const list <Ident
// -----------------------------------------------------------------------------
void ServerGroupChatRoomPrivate::onParticipantDeviceLeft (const shared_ptr<const CallSession> &session) {}
void ServerGroupChatRoomPrivate::onParticipantDeviceLeft (const shared_ptr<ParticipantDevice> &device) {}
// -----------------------------------------------------------------------------
@ -187,7 +189,7 @@ void ServerGroupChatRoom::addParticipant (const IdentityAddress &, const CallSes
void ServerGroupChatRoom::addParticipants (const list<IdentityAddress> &, const CallSessionParams *, bool) {}
void ServerGroupChatRoom::removeParticipant (const shared_ptr<const Participant> &) {}
void ServerGroupChatRoom::removeParticipant (const shared_ptr<Participant> &participant) {}
void ServerGroupChatRoom::removeParticipants (const list<shared_ptr<Participant>> &) {}

View file

@ -68,7 +68,7 @@ public:
bool hasMedia
) override;
void removeParticipant (const std::shared_ptr<const Participant> &participant) override;
void removeParticipant (const std::shared_ptr<Participant> &participant) override;
void removeParticipants (const std::list<std::shared_ptr<Participant>> &participants) override;
std::shared_ptr<Participant> findParticipant (const IdentityAddress &participantAddress) const override;

View file

@ -55,7 +55,7 @@ public:
virtual const std::string &getSubject () const = 0;
virtual void join () = 0;
virtual void leave () = 0;
virtual void removeParticipant (const std::shared_ptr<const Participant> &participant) = 0;
virtual void removeParticipant (const std::shared_ptr<Participant> &participant) = 0;
virtual void removeParticipants (const std::list<std::shared_ptr<Participant>> &participants) = 0;
virtual void setParticipantAdminStatus (const std::shared_ptr<Participant> &participant, bool isAdmin) = 0;
virtual void setSubject (const std::string &subject) = 0;

View file

@ -19,8 +19,12 @@
#include "conference-p.h"
#include "conference/session/call-session-p.h"
#include "content/content.h"
#include "content/content-disposition.h"
#include "content/content-type.h"
#include "logger/logger.h"
#include "participant-p.h"
#include "xml/resource-lists.h"
// =============================================================================
@ -97,7 +101,7 @@ void Conference::join () {}
void Conference::leave () {}
void Conference::removeParticipant (const shared_ptr<const Participant> &participant) {
void Conference::removeParticipant (const shared_ptr<Participant> &participant) {
lError() << "Conference class does not handle removeParticipant() generically";
}
@ -154,6 +158,8 @@ shared_ptr<ParticipantDevice> Conference::findParticipantDevice (const shared_pt
return nullptr;
}
// -----------------------------------------------------------------------------
bool Conference::isMe (const IdentityAddress &addr) const {
L_D();
IdentityAddress cleanedAddr(addr);
@ -163,4 +169,46 @@ bool Conference::isMe (const IdentityAddress &addr) const {
return cleanedMeAddr == cleanedAddr;
}
// -----------------------------------------------------------------------------
string Conference::getResourceLists (const list<IdentityAddress> &addresses) const {
Xsd::ResourceLists::ResourceLists rl = Xsd::ResourceLists::ResourceLists();
Xsd::ResourceLists::ListType l = Xsd::ResourceLists::ListType();
for (const auto &addr : addresses) {
Xsd::ResourceLists::EntryType entry = Xsd::ResourceLists::EntryType(addr.asString());
l.getEntry().push_back(entry);
}
rl.getList().push_back(l);
Xsd::XmlSchema::NamespaceInfomap map;
stringstream xmlBody;
serializeResourceLists(xmlBody, rl, map);
return xmlBody.str();
}
// -----------------------------------------------------------------------------
list<IdentityAddress> Conference::parseResourceLists (const Content &content) {
if ((content.getContentType() == ContentType::ResourceLists)
&& ((content.getContentDisposition().weakEqual(ContentDisposition::RecipientList))
|| (content.getContentDisposition().weakEqual(ContentDisposition::RecipientListHistory))
)
) {
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 list<IdentityAddress>();
}
LINPHONE_END_NAMESPACE

View file

@ -34,6 +34,7 @@ class CallSession;
class CallSessionListener;
class CallSessionPrivate;
class ConferencePrivate;
class Content;
class ParticipantDevice;
class LINPHONE_PUBLIC Conference :
@ -62,11 +63,14 @@ public:
const std::string &getSubject () const override;
void join () override;
void leave () override;
void removeParticipant (const std::shared_ptr<const Participant> &participant) override;
void removeParticipant (const std::shared_ptr<Participant> &participant) override;
void removeParticipants (const std::list<std::shared_ptr<Participant>> &participants) override;
void setParticipantAdminStatus (const std::shared_ptr<Participant> &participant, bool isAdmin) override;
void setSubject (const std::string &subject) override;
std::string getResourceLists (const std::list<IdentityAddress> &addresses) const;
static std::list<IdentityAddress> parseResourceLists (const Content &content);
protected:
explicit Conference (
ConferencePrivate &p,

View file

@ -17,14 +17,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "content/content.h"
#include "content/content-disposition.h"
#include "content/content-type.h"
#include "handlers/local-conference-event-handler.h"
#include "local-conference-p.h"
#include "logger/logger.h"
#include "participant-p.h"
#include "xml/resource-lists.h"
// =============================================================================
@ -59,7 +55,7 @@ void LocalConference::addParticipant (const IdentityAddress &addr, const CallSes
d->activeParticipant = participant;
}
void LocalConference::removeParticipant (const shared_ptr<const Participant> &participant) {
void LocalConference::removeParticipant (const shared_ptr<Participant> &participant) {
L_D();
for (const auto &p : d->participants) {
if (participant->getAddress() == p->getAddress()) {
@ -69,25 +65,4 @@ void LocalConference::removeParticipant (const shared_ptr<const Participant> &pa
}
}
list<IdentityAddress> LocalConference::parseResourceLists (const Content &content) {
if ((content.getContentType() == ContentType::ResourceLists)
&& (content.getContentDisposition() == ContentDisposition::RecipientList)
) {
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 list<IdentityAddress>();
}
LINPHONE_END_NAMESPACE

View file

@ -26,7 +26,6 @@
LINPHONE_BEGIN_NAMESPACE
class Content;
class LocalConferencePrivate;
class LocalConference : public Conference {
@ -38,9 +37,7 @@ public:
/* ConferenceInterface */
void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override;
void removeParticipant (const std::shared_ptr<const Participant> &participant) override;
static std::list<IdentityAddress> parseResourceLists (const Content &content);
void removeParticipant (const std::shared_ptr<Participant> &participant) override;
private:
L_DECLARE_PRIVATE(LocalConference);

View file

@ -29,7 +29,7 @@ LINPHONE_BEGIN_NAMESPACE
ParticipantDevice::ParticipantDevice () {}
ParticipantDevice::ParticipantDevice (const Participant *participant, const IdentityAddress &gruu)
ParticipantDevice::ParticipantDevice (Participant *participant, const IdentityAddress &gruu)
: mParticipant(participant), mGruu(gruu) {}
ParticipantDevice::~ParticipantDevice () {

View file

@ -44,13 +44,13 @@ public:
};
ParticipantDevice ();
explicit ParticipantDevice (const Participant *participant, const IdentityAddress &gruu);
explicit ParticipantDevice (Participant *participant, const IdentityAddress &gruu);
virtual ~ParticipantDevice ();
bool operator== (const ParticipantDevice &device) const;
inline const IdentityAddress &getAddress () const { return mGruu; }
const Participant *getParticipant () const { return mParticipant; }
Participant *getParticipant () const { return mParticipant; }
inline std::shared_ptr<CallSession> getSession () const { return mSession; }
inline void setSession (std::shared_ptr<CallSession> session) { mSession = session; }
inline State getState () const { return mState; }
@ -63,7 +63,7 @@ public:
bool isValid () const { return mGruu.isValid(); }
private:
const Participant *mParticipant = nullptr;
Participant *mParticipant = nullptr;
IdentityAddress mGruu;
std::shared_ptr<CallSession> mSession;
LinphoneEvent *mConferenceSubscribeEvent = nullptr;

View file

@ -21,7 +21,6 @@
#include "logger/logger.h"
#include "participant-p.h"
#include "remote-conference-p.h"
#include "xml/resource-lists.h"
// =============================================================================
@ -59,7 +58,7 @@ void RemoteConference::addParticipant (const IdentityAddress &addr, const CallSe
d->activeParticipant = participant;
}
void RemoteConference::removeParticipant (const shared_ptr<const Participant> &participant) {
void RemoteConference::removeParticipant (const shared_ptr<Participant> &participant) {
L_D();
for (const auto &p : d->participants) {
if (participant->getAddress() == p->getAddress()) {
@ -69,21 +68,6 @@ void RemoteConference::removeParticipant (const shared_ptr<const Participant> &p
}
}
string RemoteConference::getResourceLists (const list<IdentityAddress> &addresses) const {
Xsd::ResourceLists::ResourceLists rl = Xsd::ResourceLists::ResourceLists();
Xsd::ResourceLists::ListType l = Xsd::ResourceLists::ListType();
for (const auto &addr : addresses) {
Xsd::ResourceLists::EntryType entry = Xsd::ResourceLists::EntryType(addr.asString());
l.getEntry().push_back(entry);
}
rl.getList().push_back(l);
Xsd::XmlSchema::NamespaceInfomap map;
stringstream xmlBody;
serializeResourceLists(xmlBody, rl, map);
return xmlBody.str();
}
// -----------------------------------------------------------------------------
void RemoteConference::onConferenceCreated (const IdentityAddress &) {}

View file

@ -38,9 +38,7 @@ public:
/* ConferenceInterface */
void addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) override;
void removeParticipant (const std::shared_ptr<const Participant> &participant) override;
std::string getResourceLists (const std::list<IdentityAddress> &addresses) const;
void removeParticipant (const std::shared_ptr<Participant> &participant) override;
protected:
/* ConferenceListener */

View file

@ -63,10 +63,13 @@ ContentDisposition &ContentDisposition::operator= (const ContentDisposition &oth
return *this;
}
bool ContentDisposition::operator== (const ContentDisposition &other) const {
bool ContentDisposition::weakEqual (const ContentDisposition &other) const {
L_D();
return d->disposition == other.getPrivate()->disposition
&& getParameter() == other.getParameter();
return d->disposition == other.getPrivate()->disposition;
}
bool ContentDisposition::operator== (const ContentDisposition &other) const {
return weakEqual(other) && (getParameter() == other.getParameter());
}
bool ContentDisposition::operator!= (const ContentDisposition &other) const {

View file

@ -35,6 +35,7 @@ public:
ContentDisposition &operator= (const ContentDisposition &other);
bool weakEqual (const ContentDisposition &other) const;
bool operator== (const ContentDisposition &other) const;
bool operator!= (const ContentDisposition &other) const;

View file

@ -103,10 +103,12 @@ ContentType &ContentType::operator= (const ContentType &other) {
return *this;
}
bool ContentType::weakEqual (const ContentType &other) const {
return (getType() == other.getType()) && (getSubType() == other.getSubType());
}
bool ContentType::operator== (const ContentType &other) const {
return getType() == other.getType() &&
getSubType() == other.getSubType() &&
getParameter() == other.getParameter();
return weakEqual(other) && (getParameter() == other.getParameter());
}
bool ContentType::operator!= (const ContentType &other) const {

View file

@ -37,6 +37,7 @@ public:
ContentType &operator= (const ContentType &other);
bool weakEqual (const ContentType &other) const;
bool operator== (const ContentType &other) const;
bool operator!= (const ContentType &other) const;

View file

@ -100,7 +100,7 @@ shared_ptr<AbstractChatRoom> CorePrivate::createBasicChatRoom (
return chatRoom;
}
shared_ptr<AbstractChatRoom> CorePrivate::createClientGroupChatRoom (const string &subject, const string &uri, bool fallback) {
shared_ptr<AbstractChatRoom> CorePrivate::createClientGroupChatRoom (const string &subject, const string &uri, const Content &content, bool fallback) {
L_Q();
string usedUri;
@ -135,7 +135,7 @@ shared_ptr<AbstractChatRoom> CorePrivate::createClientGroupChatRoom (const strin
shared_ptr<AbstractChatRoom> chatRoom;
{
shared_ptr<ClientGroupChatRoom> clientGroupChatRoom = make_shared<ClientGroupChatRoom>(
q->getSharedFromThis(), usedUri, IdentityAddress(from), subject
q->getSharedFromThis(), usedUri, IdentityAddress(from), subject, content
);
ClientGroupChatRoomPrivate *dClientGroupChatRoom = clientGroupChatRoom->getPrivate();

View file

@ -61,7 +61,7 @@ public:
void insertChatRoom (const std::shared_ptr<AbstractChatRoom> &chatRoom);
void insertChatRoomWithDb (const std::shared_ptr<AbstractChatRoom> &chatRoom);
std::shared_ptr<AbstractChatRoom> createBasicChatRoom (const ChatRoomId &chatRoomId, AbstractChatRoom::CapabilitiesMask capabilities);
std::shared_ptr<AbstractChatRoom> createClientGroupChatRoom (const std::string &subject, const std::string &uri = "", bool fallback = true);
std::shared_ptr<AbstractChatRoom> createClientGroupChatRoom (const std::string &subject, const std::string &uri = "", const Content &content = Content(), bool fallback = true);
void replaceChatRoom (const std::shared_ptr<AbstractChatRoom> &replacedChatRoom, const std::shared_ptr<AbstractChatRoom> &newChatRoom);
std::unique_ptr<MainDb> mainDb;

View file

@ -237,7 +237,7 @@ void SalCallOp::cancelling_invite(const SalErrorInfo *info) {
Content SalCallOp::extract_body(belle_sip_message_t *message) {
Content body;
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(message, belle_sip_header_content_type_t);
belle_sip_header_content_disposition_t *contentDisposition = belle_sip_message_get_header_by_type(message, belle_sip_header_content_disposition_t);
belle_sip_header_content_disposition_t *contentDispositionHeader = belle_sip_message_get_header_by_type(message, belle_sip_header_content_disposition_t);
belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(message, belle_sip_header_content_length_t);
const char *type_str = content_type ? belle_sip_header_content_type_get_type(content_type) : NULL;
const char *subtype_str = content_type ? belle_sip_header_content_type_get_subtype(content_type) : NULL;
@ -245,10 +245,13 @@ Content SalCallOp::extract_body(belle_sip_message_t *message) {
const char *body_str = belle_sip_message_get_body(message);
if (type_str && subtype_str) body.setContentType(ContentType(type_str, subtype_str));
if (contentDisposition)
body.setContentDisposition(
ContentDisposition(belle_sip_header_content_disposition_get_content_disposition(contentDisposition))
);
if (contentDispositionHeader) {
auto contentDisposition = ContentDisposition(belle_sip_header_content_disposition_get_content_disposition(contentDispositionHeader));
if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contentDispositionHeader), "handling")) {
contentDisposition.setParameter("handling=" + string(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(contentDispositionHeader), "handling")));
}
body.setContentDisposition(contentDisposition);
}
if (length > 0 && body_str) body.setBody(body_str, length);
return body;
}
@ -497,7 +500,9 @@ void SalCallOp::process_response_cb(void *op_base, const belle_sip_response_even
}
break;
case BELLE_SIP_DIALOG_TERMINATED: {
if (strcmp("INVITE",method)==0 && code >= 300){
if ((code >= 300)
&& ((strcmp("INVITE", method) == 0) || (strcmp("BYE", method) == 0))
) {
op->set_error(response, TRUE);
}
}

View file

@ -27,6 +27,8 @@
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
void BackgroundTask::sHandleTimeout (void *context) {
@ -43,7 +45,7 @@ void BackgroundTask::handleSalTimeout () {
stop();
}
void BackgroundTask::start (const std::shared_ptr<Core> &core, int maxDurationSeconds) {
void BackgroundTask::start (const shared_ptr<Core> &core, int maxDurationSeconds) {
if (mName.empty()) {
lError() << "No name was set on background task";
return;

View file

@ -35,23 +35,17 @@ class Core;
class BackgroundTask {
public:
BackgroundTask () {}
BackgroundTask (const std::string &name) {}
virtual ~BackgroundTask () {
stop();
}
BackgroundTask (const std::string &name) : mName(name) {}
virtual ~BackgroundTask () { stop(); }
void setName (const std::string &name) {
mName = name;
}
void setName (const std::string &name) { mName = name; }
const std::string &getName () const {
return mName;
}
const std::string &getName () const { return mName; }
/**
* Start a long running task for at most max_duration_seconds, after which it is automatically terminated
*/
void start (const std::shared_ptr<Core> &core, int maxDurationSeconds = 15 * 60); // 15 min by default, like on iOS
void start (const std::shared_ptr<Core> &core, int maxDurationSeconds = 15 * 60); // 15 min by default, like on iOS
void stop ();
protected:

View file

@ -69,6 +69,7 @@ static void chat_room_participant_device_added (LinphoneChatRoom *cr, const Linp
static void chat_room_state_changed (LinphoneChatRoom *cr, LinphoneChatRoomState newState) {
LinphoneCore *core = linphone_chat_room_get_core(cr);
LinphoneCoreManager *manager = (LinphoneCoreManager *)linphone_core_get_user_data(core);
ms_message("ChatRoom [%p] state changed: %d", cr, newState);
switch (newState) {
case LinphoneChatRoomStateNone:
break;
@ -105,6 +106,12 @@ static void chat_room_subject_changed (LinphoneChatRoom *cr, const LinphoneEvent
manager->stat.number_of_subject_changed++;
}
static void chat_room_all_information_received (LinphoneChatRoom *cr) {
LinphoneCore *core = linphone_chat_room_get_core(cr);
LinphoneCoreManager *manager = (LinphoneCoreManager *)linphone_core_get_user_data(core);
manager->stat.number_of_LinphoneChatRoomAllInformationReceived++;
}
static void core_chat_room_state_changed (LinphoneCore *core, LinphoneChatRoom *cr, LinphoneChatRoomState state) {
if (state == LinphoneChatRoomStateInstantiated) {
LinphoneChatRoomCbs *cbs = linphone_factory_create_chat_room_cbs(linphone_factory_get());
@ -115,6 +122,7 @@ static void core_chat_room_state_changed (LinphoneCore *core, LinphoneChatRoom *
linphone_chat_room_cbs_set_state_changed(cbs, chat_room_state_changed);
linphone_chat_room_cbs_set_subject_changed(cbs, chat_room_subject_changed);
linphone_chat_room_cbs_set_participant_device_added(cbs, chat_room_participant_device_added);
linphone_chat_room_cbs_set_all_information_received(cbs, chat_room_all_information_received);
linphone_chat_room_add_callbacks(cr, cbs);
linphone_chat_room_cbs_unref(cbs);
}
@ -180,9 +188,9 @@ static void _send_file_plus_text(LinphoneChatRoom* cr, const char *sendFilepath,
cbs = linphone_chat_message_get_callbacks(msg);
linphone_chat_message_cbs_set_file_transfer_send(cbs, tester_file_transfer_send);
linphone_chat_message_cbs_set_msg_state_changed(cbs,liblinphone_tester_chat_message_msg_state_changed);
linphone_chat_message_cbs_set_msg_state_changed(cbs, liblinphone_tester_chat_message_msg_state_changed);
linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication);
linphone_chat_room_send_chat_message(cr, msg);
linphone_chat_message_send(msg);
linphone_content_unref(content);
linphone_chat_message_unref(msg);
}
@ -255,6 +263,7 @@ static void start_core_for_conference(bctbx_list_t *coreManagerList) {
static LinphoneChatRoom * check_creation_chat_room_client_side(bctbx_list_t *lcs, LinphoneCoreManager *lcm, stats *initialStats, const LinphoneAddress *confAddr, const char* subject, int participantNumber, bool_t isAdmin) {
BC_ASSERT_TRUE(wait_for_list(lcs, &lcm->stat.number_of_LinphoneChatRoomStateCreationPending, initialStats->number_of_LinphoneChatRoomStateCreationPending + 1, 5000));
BC_ASSERT_TRUE(wait_for_list(lcs, &lcm->stat.number_of_LinphoneChatRoomStateCreated, initialStats->number_of_LinphoneChatRoomStateCreated + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(lcs, &lcm->stat.number_of_LinphoneChatRoomAllInformationReceived, initialStats->number_of_LinphoneChatRoomAllInformationReceived + 1, 10000));
char *deviceIdentity = linphone_core_get_device_identity(lcm->lc);
LinphoneAddress *localAddr = linphone_address_new(deviceIdentity);
bctbx_free(deviceIdentity);
@ -284,6 +293,7 @@ static LinphoneChatRoom * create_chat_room_client_side(bctbx_list_t *lcs, Linpho
// Check that the chat room is correctly created on Marie's side and that the participants are added
BC_ASSERT_TRUE(wait_for_list(lcs, &lcm->stat.number_of_LinphoneChatRoomStateCreationPending, initialStats->number_of_LinphoneChatRoomStateCreationPending + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(lcs, &lcm->stat.number_of_LinphoneChatRoomStateCreated, initialStats->number_of_LinphoneChatRoomStateCreated + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(lcs, &lcm->stat.number_of_LinphoneChatRoomAllInformationReceived, initialStats->number_of_LinphoneChatRoomAllInformationReceived + 1, 10000));
BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(chatRoom),
(expectedParticipantSize >= 0) ? expectedParticipantSize : (int)bctbx_list_size(participantsAddresses),
int, "%d");
@ -1528,13 +1538,14 @@ static void group_chat_room_reinvited_after_removed_base (bool_t offline_when_re
bctbx_list_t *tmpCoresManagerList = bctbx_list_append(NULL, laure);
bctbx_list_t *tmpCoresList = init_core_for_conference(tmpCoresManagerList);
bctbx_list_free(tmpCoresManagerList);
initialLaureStats = laure->stat;
linphone_core_manager_start(laure, TRUE);
coresList = bctbx_list_concat(coresList, tmpCoresList);
coresManagerList = bctbx_list_append(coresManagerList, laure);
}
if (!offline_when_reinvited)
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomStateTerminated, initialLaureStats.number_of_LinphoneChatRoomStateTerminated + 1, 3000));
wait_for_list(coresList,0, 1, 2000);
initialLaureStats = laure->stat;
// Marie adds Laure to the chat room
participantsAddresses = bctbx_list_append(participantsAddresses, laureAddr);
@ -1550,16 +1561,13 @@ static void group_chat_room_reinvited_after_removed_base (bool_t offline_when_re
bctbx_list_t *tmpCoresManagerList = bctbx_list_append(NULL, laure);
bctbx_list_t *tmpCoresList = init_core_for_conference(tmpCoresManagerList);
bctbx_list_free(tmpCoresManagerList);
initialLaureStats = laure->stat;
linphone_core_manager_start(laure, TRUE);
coresList = bctbx_list_concat(coresList, tmpCoresList);
coresManagerList = bctbx_list_append(coresManagerList, laure);
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomStateCreationPending, initialLaureStats.number_of_LinphoneChatRoomStateCreationPending + 1, 5000));
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomStateCreated, initialLaureStats.number_of_LinphoneChatRoomStateCreated + 2, 5000));
} else {
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomStateCreationPending, initialLaureStats.number_of_LinphoneChatRoomStateCreationPending + 1, 5000));
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomStateCreated, initialLaureStats.number_of_LinphoneChatRoomStateCreated + 1, 5000));
}
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomStateCreationPending, initialLaureStats.number_of_LinphoneChatRoomStateCreationPending + 1, 5000));
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomStateCreated, initialLaureStats.number_of_LinphoneChatRoomStateCreated + 1, 5000));
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomAllInformationReceived, initialLaureStats.number_of_LinphoneChatRoomAllInformationReceived + 1, 5000));
BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 2, int, "%d");
BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d");
char *laureIdentity = linphone_core_get_device_identity(laure->lc);
@ -2301,12 +2309,14 @@ static void group_chat_room_migrate_from_basic_chat_room (void) {
linphone_chat_message_unref(msg);
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_LinphoneChatRoomStateCreated, initialMarieStats.number_of_LinphoneChatRoomStateCreated + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomAllInformationReceived, initialMarieStats.number_of_LinphoneChatRoomAllInformationReceived + 1, 10000));
BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(marieCr) & LinphoneChatRoomCapabilitiesConference);
BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 1, int, "%d");
BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(marieCr), 2, int, "%d");
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomStateCreationPending, initialPaulineStats.number_of_LinphoneChatRoomStateCreationPending + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomStateCreated, initialPaulineStats.number_of_LinphoneChatRoomStateCreated + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomAllInformationReceived, initialPaulineStats.number_of_LinphoneChatRoomAllInformationReceived + 1, 10000));
BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(paulineCr) & LinphoneChatRoomCapabilitiesConference);
BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 1, int, "%d");
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 1, 1000));
@ -2440,12 +2450,14 @@ static void group_chat_room_migrate_from_basic_to_client_fail (void) {
linphone_chat_message_send(msg);
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateCreationPending, initialMarieStats.number_of_LinphoneChatRoomStateCreationPending + 2, 10000));
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateCreated, initialMarieStats.number_of_LinphoneChatRoomStateCreated + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomAllInformationReceived, initialMarieStats.number_of_LinphoneChatRoomAllInformationReceived + 1, 10000));
BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(marieCr) & LinphoneChatRoomCapabilitiesConference);
BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 1, int, "%d");
BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(marieCr), 5, int, "%d");
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomStateCreationPending, initialPaulineStats.number_of_LinphoneChatRoomStateCreationPending + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomStateCreated, initialPaulineStats.number_of_LinphoneChatRoomStateCreated + 1, 10000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomAllInformationReceived, initialPaulineStats.number_of_LinphoneChatRoomAllInformationReceived + 1, 10000));
BC_ASSERT_TRUE(linphone_chat_room_get_capabilities(paulineCr) & LinphoneChatRoomCapabilitiesConference);
BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 1, int, "%d");
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 3, 1000));
@ -2792,10 +2804,10 @@ static void group_chat_room_unique_one_to_one_chat_room_recreated_from_message_w
static void group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2 (void) {
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
/*create a second device for marie, but it is inactive after registration in this test*/
// Create a second device for Marie, but it is inactive after registration in this test
LinphoneCoreManager *marie2 = linphone_core_manager_create("marie_rc");
/*Create a seconde device for pauline, but again inactivate after registration*/
LinphoneCoreManager *pauline2 = linphone_core_manager_create("marie_rc");
// Create a second device for Pauline, but again inactivate it after registration
LinphoneCoreManager *pauline2 = linphone_core_manager_create("pauline_rc");
bctbx_list_t *coresManagerList = NULL;
bctbx_list_t *participantsAddresses = NULL;
coresManagerList = bctbx_list_append(coresManagerList, marie);
@ -2807,6 +2819,8 @@ static void group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc)));
stats initialMarieStats = marie->stat;
stats initialPaulineStats = pauline->stat;
stats initialMarie2Stats = marie2->stat;
stats initialPauline2Stats = pauline2->stat;
linphone_core_set_network_reachable(marie2->lc, FALSE);
linphone_core_set_network_reachable(pauline2->lc, FALSE);
@ -2852,13 +2866,22 @@ static void group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2
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), textMessage);
linphone_chat_message_unref(message);
// Clean db from chat room
linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
}
linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
wait_for_list(coresList, 0, 1, 2000);
// Clean db from chat room
linphone_core_set_network_reachable(marie2->lc, TRUE);
linphone_core_set_network_reachable(pauline2->lc, TRUE);
BC_ASSERT_TRUE(wait_for_list(coresList, &marie2->stat.number_of_LinphoneChatRoomStateCreationPending, initialMarie2Stats.number_of_LinphoneChatRoomStateCreationPending + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &marie2->stat.number_of_LinphoneChatRoomStateCreated, initialMarie2Stats.number_of_LinphoneChatRoomStateCreated + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline2->stat.number_of_LinphoneChatRoomStateCreationPending, initialPauline2Stats.number_of_LinphoneChatRoomStateCreationPending + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline2->stat.number_of_LinphoneChatRoomStateCreated, initialPauline2Stats.number_of_LinphoneChatRoomStateCreated + 1, 3000));
linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateTerminated, initialMarieStats.number_of_LinphoneChatRoomStateTerminated + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomStateTerminated, initialPaulineStats.number_of_LinphoneChatRoomStateTerminated + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &marie2->stat.number_of_LinphoneChatRoomStateTerminated, initialMarie2Stats.number_of_LinphoneChatRoomStateTerminated + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline2->stat.number_of_LinphoneChatRoomStateTerminated, initialPauline2Stats.number_of_LinphoneChatRoomStateTerminated + 1, 3000));
BC_ASSERT_EQUAL(linphone_core_get_call_history_size(marie->lc), 0, int,"%i");
BC_ASSERT_EQUAL(linphone_core_get_call_history_size(pauline->lc), 0, int,"%i");
BC_ASSERT_PTR_NULL(linphone_core_get_call_logs(marie->lc));
@ -2867,8 +2890,6 @@ static void group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2
linphone_address_unref(confAddr);
bctbx_list_free(coresList);
bctbx_list_free(coresManagerList);
linphone_core_set_network_reachable(marie2->lc, TRUE);
linphone_core_set_network_reachable(pauline2->lc, TRUE);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(marie2);
@ -2947,6 +2968,9 @@ static void group_chat_room_join_one_to_one_chat_room_with_a_new_device (void) {
linphone_chat_message_unref(message);
// Clean db from chat room
int previousNbRegistrationOk = marie1->stat.number_of_LinphoneRegistrationOk;
linphone_core_set_network_reachable(marie1->lc, TRUE);
wait_for_until(marie1->lc, NULL, &marie1->stat.number_of_LinphoneRegistrationOk, previousNbRegistrationOk + 1, 2000);
linphone_core_manager_delete_chat_room(marie2, marie2Cr, coresList);
linphone_core_delete_chat_room(marie1->lc, marie1Cr);
linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
@ -3272,7 +3296,7 @@ test_t group_chat_tests[] = {
TEST_NO_TAG("Unique one-to-one chatroom", group_chat_room_unique_one_to_one_chat_room),
TEST_NO_TAG("Unique one-to-one chatroom recreated from message", group_chat_room_unique_one_to_one_chat_room_recreated_from_message),
TEST_ONE_TAG("Unique one-to-one chatroom recreated from message with app restart", group_chat_room_unique_one_to_one_chat_room_recreated_from_message_with_app_restart, "LeaksMemory"),
TEST_NO_TAG("Join one-to-one chat room with a new device", group_chat_room_join_one_to_one_chat_room_with_a_new_device),
TEST_ONE_TAG("Join one-to-one chat room with a new device", group_chat_room_join_one_to_one_chat_room_with_a_new_device, "LeaksMemory"),
TEST_NO_TAG("New unique one-to-one chatroom after both participants left", group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left),
TEST_NO_TAG("Unique one-to-one chatroom re-created from the party that deleted it, with inactive devices", group_chat_room_unique_one_to_one_chat_room_recreated_from_message_2),
TEST_NO_TAG("IMDN for group chat room", imdn_for_group_chat_room),

View file

@ -182,6 +182,7 @@ typedef struct _stats {
int number_of_LinphoneIsComposingIdleReceived;
int progress_of_LinphoneFileTransfer;
int number_of_LinphoneChatRoomAllInformationReceived;
int number_of_LinphoneChatRoomStateInstantiated;
int number_of_LinphoneChatRoomStateCreationPending;
int number_of_LinphoneChatRoomStateCreated;