diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 4f416f565..d1fff0d83 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -773,7 +773,7 @@ static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { return; } -int sal_call(SalOp *op, const char *from, const char *to){ +int sal_call(SalOp *op, const char *from, const char *to, const char *subject){ belle_sip_request_t* invite; op->dir=SalOpDirOutgoing; @@ -789,6 +789,8 @@ int sal_call(SalOp *op, const char *from, const char *to){ } sal_op_fill_invite(op,invite); + if (subject) + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite), belle_sip_header_create("Subject", subject)); sal_op_call_fill_cbs(op); if (op->replaces){ @@ -1036,7 +1038,7 @@ int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ during a very early state of outgoing call initiation (the dialog has not been created yet). */ const char *from = sal_op_get_from(op); const char *to = sal_op_get_to(op); - return sal_call(op, from, to); + return sal_call(op, from, to, subject); } state = belle_sip_dialog_get_state(op->dialog); diff --git a/coreapi/chat.c b/coreapi/chat.c index 7059cb04b..a458facac 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -125,8 +125,8 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd return ret; } -LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc) { - LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc); +LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject) { + LinphoneChatRoom *cr = _linphone_client_group_chat_room_new(lc, subject); lc->chatrooms = bctbx_list_append(lc->chatrooms, cr); return cr; } diff --git a/coreapi/private.h b/coreapi/private.h index b3a9d0ce7..80cea1623 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -460,7 +460,7 @@ void _linphone_proxy_config_release_ops(LinphoneProxyConfig *obj); /*chat*/ LinphoneChatRoom * linphone_chat_room_new(LinphoneCore *core, const LinphoneAddress *addr); -LinphoneChatRoom *_linphone_client_group_chat_room_new(LinphoneCore *core); +LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *subject); void linphone_chat_room_release(LinphoneChatRoom *cr); void linphone_chat_room_set_call(LinphoneChatRoom *cr, LinphoneCall *call); bctbx_list_t * linphone_chat_room_get_transient_messages(const LinphoneChatRoom *cr); diff --git a/coreapi/sal/sal.h b/coreapi/sal/sal.h index bcda97dde..5e0188feb 100644 --- a/coreapi/sal/sal.h +++ b/coreapi/sal/sal.h @@ -742,7 +742,7 @@ void sal_op_set_event(SalOp *op, const char *event); /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); -int sal_call(SalOp *h, const char *from, const char *to); +int sal_call(SalOp *h, const char *from, const char *to, const char *subject); int sal_call_notify_ringing(SalOp *h, bool_t early_media); /*accept an incoming call or, during a call accept a reINVITE*/ int sal_call_accept(SalOp*h); diff --git a/include/linphone/core.h b/include/linphone/core.h index 231557035..55b6fc282 100644 --- a/include/linphone/core.h +++ b/include/linphone/core.h @@ -4837,9 +4837,10 @@ LINPHONE_PUBLIC const char *linphone_core_get_chat_database_path(const LinphoneC * at the client-side and is empty. Pou need to call linphone_chat_room_add_participants() to * create at the server side and add participants to it. * @param[in] lc A #LinphoneCore object + * @param[in] subject The subject of the group chat room * @return The newly created client-side group chat room. */ -LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_client_group_chat_room(LinphoneCore *lc, const char *subject); /** * Get a chat room whose peer is the supplied address. If it does not exist yet, it will be created. diff --git a/src/address/address.cpp b/src/address/address.cpp index 17b9ed9bf..8de8d1f90 100644 --- a/src/address/address.cpp +++ b/src/address/address.cpp @@ -67,6 +67,10 @@ bool Address::operator== (const Address &address) const { return equal(address); } +bool Address::operator< (const Address &address) const { + return asString() < address.asString(); +} + bool Address::isValid () const { L_D(const Address); return static_cast(d->internalAddress); diff --git a/src/address/address.h b/src/address/address.h index 679ba572b..eb3d74ed0 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -38,6 +38,8 @@ public: bool operator== (const Address &address) const; + bool operator< (const Address &address) const; + bool isValid () const; const std::string &getScheme () const; diff --git a/src/c-wrapper/api/c-chat-room.cpp b/src/c-wrapper/api/c-chat-room.cpp index 652ccb466..558b8e56c 100644 --- a/src/c-wrapper/api/c-chat-room.cpp +++ b/src/c-wrapper/api/c-chat-room.cpp @@ -277,7 +277,7 @@ LinphoneChatRoom *linphone_chat_room_new (LinphoneCore *core, const LinphoneAddr return cr; } -LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core) { +LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core, const char *subject) { const char *factoryUri = linphone_core_get_conference_factory_uri(core); if (!factoryUri) return nullptr; @@ -291,7 +291,7 @@ LinphoneChatRoom *_linphone_client_group_chat_room_new (LinphoneCore *core) { from = linphone_core_get_primary_contact(core); LinphonePrivate::Address me(from); LinphoneChatRoom *cr = L_INIT(ChatRoom); - L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me)); + L_SET_CPP_PTR_FROM_C_OBJECT(cr, make_shared(core, me, subject ? subject : "")); L_GET_PRIVATE_FROM_C_OBJECT(cr)->setState(LinphonePrivate::ChatRoom::State::Instantiated); return cr; } diff --git a/src/call/call.cpp b/src/call/call.cpp index 9c9e6f613..929bfceca 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -97,7 +97,7 @@ void CallPrivate::startIncomingNotification () { } int CallPrivate::startInvite (const Address *destination) { - return getActiveSession()->startInvite(destination); + return getActiveSession()->startInvite(destination, ""); } // ----------------------------------------------------------------------------- diff --git a/src/chat/client-group-chat-room-p.h b/src/chat/client-group-chat-room-p.h index 346faf869..ef642bc6c 100644 --- a/src/chat/client-group-chat-room-p.h +++ b/src/chat/client-group-chat-room-p.h @@ -31,10 +31,12 @@ LINPHONE_BEGIN_NAMESPACE class ClientGroupChatRoomPrivate : public ChatRoomPrivate { public: - ClientGroupChatRoomPrivate (LinphoneCore *core); + ClientGroupChatRoomPrivate (LinphoneCore *core, const std::string &subject); virtual ~ClientGroupChatRoomPrivate () = default; private: + std::string subject; + L_DECLARE_PUBLIC(ClientGroupChatRoom); }; diff --git a/src/chat/client-group-chat-room.cpp b/src/chat/client-group-chat-room.cpp index 912383cf4..bfd078e57 100644 --- a/src/chat/client-group-chat-room.cpp +++ b/src/chat/client-group-chat-room.cpp @@ -19,6 +19,7 @@ #include "client-group-chat-room-p.h" #include "c-wrapper/c-wrapper.h" #include "conference/participant-p.h" +#include "content/content.h" #include "logger/logger.h" // ============================================================================= @@ -27,18 +28,15 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core) : ChatRoomPrivate(core) {} +ClientGroupChatRoomPrivate::ClientGroupChatRoomPrivate (LinphoneCore *core, const string &subject) + : ChatRoomPrivate(core), subject(subject) {} // ============================================================================= -ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me) - : ChatRoom(*new ChatRoomPrivate(core)), RemoteConference(core, me, nullptr) { +ClientGroupChatRoom::ClientGroupChatRoom (LinphoneCore *core, const Address &me, const string &subject) + : ChatRoom(*new ClientGroupChatRoomPrivate(core, subject)), RemoteConference(core, me, nullptr) { string factoryUri = linphone_core_get_conference_factory_uri(core); focus = make_shared(factoryUri); - CallSessionParams csp; - shared_ptr session = focus->getPrivate()->createSession(*this, &csp, false, this); - session->configure(LinphoneCallOutgoing, nullptr, nullptr, me, focus->getAddress()); - // TODO } // ----------------------------------------------------------------------------- @@ -51,10 +49,25 @@ shared_ptr ClientGroupChatRoom::addParticipant (const Address &addr void ClientGroupChatRoom::addParticipants (const list
&addresses, const CallSessionParams *params, bool hasMedia) { L_D(ClientGroupChatRoom); + if (addresses.empty()) + return; + list
sortedAddresses(addresses); + sortedAddresses.sort(); + sortedAddresses.unique(); if (d->state == ChatRoom::State::Instantiated) { - shared_ptr session = focus->getPrivate()->getSession(); + Content content; + content.setBody(getResourceLists(sortedAddresses)); + content.setContentType("application/resource-lists+xml"); + content.setContentDisposition("recipient-list"); + lInfo() << "Body size: " << content.getSize() << endl << "Body:" << endl << content.getBodyAsString(); + CallSessionParams csp; + if (params) + csp = *params; + csp.addCustomHeader("Require", "recipient-list-invite"); + shared_ptr session = focus->getPrivate()->createSession(*this, &csp, false, this); + session->configure(LinphoneCallOutgoing, nullptr, nullptr, me->getAddress(), focus->getAddress()); session->initiateOutgoing(); - session->startInvite(nullptr); + session->startInvite(nullptr, d->subject); d->setState(ChatRoom::State::CreationPending); } // TODO diff --git a/src/chat/client-group-chat-room.h b/src/chat/client-group-chat-room.h index 8207b62dd..eab0f5a28 100644 --- a/src/chat/client-group-chat-room.h +++ b/src/chat/client-group-chat-room.h @@ -36,7 +36,7 @@ class ClientGroupChatRoomPrivate; class ClientGroupChatRoom : public ChatRoom, public RemoteConference { public: - ClientGroupChatRoom (LinphoneCore *core, const Address &me); + ClientGroupChatRoom (LinphoneCore *core, const Address &me, const std::string &subject); virtual ~ClientGroupChatRoom () = default; public: diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index d38fa5e85..64af9041d 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -311,7 +311,7 @@ void CallSessionPrivate::pingReply () { if (state == LinphoneCallOutgoingInit) { pingReplied = true; if (isReadyForInvite()) - q->startInvite(nullptr); + q->startInvite(nullptr, ""); } } @@ -770,7 +770,7 @@ void CallSession::iterate (time_t currentRealTime, bool oneSecondElapsed) { int elapsed = (int)(currentRealTime - d->log->start_date_time); if ((d->state == LinphoneCallOutgoingInit) && (elapsed >= d->core->sip_conf.delayed_timeout)) { /* Start the call even if the OPTIONS reply did not arrive */ - startInvite(nullptr); + startInvite(nullptr, ""); } if ((d->state == LinphoneCallIncomingReceived) || (d->state == LinphoneCallIncomingEarlyMedia)) { if (oneSecondElapsed) @@ -828,7 +828,7 @@ void CallSession::startIncomingNotification () { } } -int CallSession::startInvite (const Address *destination) { +int CallSession::startInvite (const Address *destination, const string &subject) { L_D(CallSession); /* Try to be best-effort in giving real local or routable contact address */ d->setContactOp(); @@ -844,7 +844,7 @@ int CallSession::startInvite (const Address *destination) { char *from = linphone_address_as_string(d->log->from); /* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */ shared_ptr ref = static_pointer_cast(shared_from_this()); - int result = sal_call(d->op, from, destinationStr.c_str()); + int result = sal_call(d->op, from, destinationStr.c_str(), subject.empty() ? nullptr : subject.c_str()); ms_free(from); if (result < 0) { if ((d->state != LinphoneCallError) && (d->state != LinphoneCallReleased)) { diff --git a/src/conference/session/call-session.h b/src/conference/session/call-session.h index 96dcbf2bf..07f8ab262 100644 --- a/src/conference/session/call-session.h +++ b/src/conference/session/call-session.h @@ -47,7 +47,7 @@ public: virtual bool initiateOutgoing (); virtual void iterate (time_t currentRealTime, bool oneSecondElapsed); virtual void startIncomingNotification (); - virtual int startInvite (const Address *destination); + virtual int startInvite (const Address *destination, const std::string &subject); LinphoneStatus terminate (const LinphoneErrorInfo *ei = nullptr); LinphoneStatus update (const CallSessionParams *csp); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index c1bce3c98..c19d8d9ce 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -2090,7 +2090,7 @@ void MediaSessionPrivate::handleIceEvents (OrtpEvent *ev) { case LinphoneCallOutgoingInit: stopStreamsForIceGathering(); if (isReadyForInvite()) - q->startInvite(nullptr); + q->startInvite(nullptr, ""); break; case LinphoneCallIdle: stopStreamsForIceGathering(); @@ -4249,7 +4249,7 @@ void MediaSession::startIncomingNotification () { CallSession::startIncomingNotification(); } -int MediaSession::startInvite (const Address *destination) { +int MediaSession::startInvite (const Address *destination, const string &subject) { L_D(MediaSession); linphone_core_stop_dtmf_stream(d->core); d->makeLocalMediaDescription(); @@ -4265,7 +4265,7 @@ int MediaSession::startInvite (const Address *destination) { sal_call_set_local_media_description(d->op, d->localDesc); } - int result = CallSession::startInvite(destination); + int result = CallSession::startInvite(destination, subject); if (result < 0) { if (d->state == LinphoneCallError) d->stopStreams(); diff --git a/src/conference/session/media-session.h b/src/conference/session/media-session.h index e27c1c7e2..27770ebb1 100644 --- a/src/conference/session/media-session.h +++ b/src/conference/session/media-session.h @@ -48,7 +48,7 @@ public: LinphoneStatus resume (); void sendVfuRequest (); void startIncomingNotification () override; - int startInvite (const Address *destination) override; + int startInvite (const Address *destination, const std::string &subject) override; void startRecording (); void stopRecording (); LinphoneStatus update (const MediaSessionParams *msp);