mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-29 09:09:21 +00:00
Merge branch 'dev_refactor_cpp' into dev_refactor_cpp_search_bar
This commit is contained in:
commit
f99300cba5
73 changed files with 1489 additions and 839 deletions
|
|
@ -198,7 +198,11 @@ const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl){
|
|||
return cl->refkey;
|
||||
}
|
||||
|
||||
LinphoneAddress *linphone_call_log_get_remote_address(const LinphoneCallLog *cl){
|
||||
const LinphoneAddress *linphone_call_log_get_local_address(const LinphoneCallLog *cl) {
|
||||
return (cl->dir == LinphoneCallIncoming) ? cl->to : cl->from;
|
||||
}
|
||||
|
||||
const LinphoneAddress *linphone_call_log_get_remote_address(const LinphoneCallLog *cl){
|
||||
return (cl->dir == LinphoneCallIncoming) ? cl->from : cl->to;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
|
||||
#include "c-wrapper/c-wrapper.h"
|
||||
#include "call/call-p.h"
|
||||
#include "chat/chat-message/chat-message-p.h"
|
||||
#include "chat/chat-room/chat-room.h"
|
||||
#include "chat/chat-room/server-group-chat-room-p.h"
|
||||
#include "conference/participant.h"
|
||||
|
|
@ -565,7 +566,7 @@ static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status)
|
|||
|
||||
// Check that the message does not belong to an already destroyed chat room - if so, do not invoke callbacks
|
||||
if (msg->getChatRoom())
|
||||
msg->updateState((LinphonePrivate::ChatMessage::State)chatStatusSal2Linphone(status));
|
||||
L_GET_PRIVATE(msg)->setState((LinphonePrivate::ChatMessage::State)chatStatusSal2Linphone(status));
|
||||
}
|
||||
|
||||
static void info_received(SalOp *op, SalBodyHandler *body_handler) {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "linphone/wrapper_utils.h"
|
||||
|
||||
#include "c-wrapper/c-wrapper.h"
|
||||
#include "call/call.h"
|
||||
#include "chat/chat-room/basic-chat-room.h"
|
||||
#include "chat/chat-room/client-group-chat-room.h"
|
||||
#include "chat/chat-room/client-group-to-basic-chat-room.h"
|
||||
|
|
@ -149,12 +150,9 @@ int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op,
|
|||
}
|
||||
|
||||
void linphone_core_real_time_text_received(LinphoneCore *lc, LinphoneChatRoom *cr, uint32_t character, LinphoneCall *call) {
|
||||
if (linphone_core_realtime_text_enabled(lc)) {
|
||||
shared_ptr<LinphonePrivate::RealTimeTextChatRoom> rttcr =
|
||||
static_pointer_cast<LinphonePrivate::RealTimeTextChatRoom>(L_GET_CPP_PTR_FROM_C_OBJECT(cr));
|
||||
L_GET_PRIVATE(rttcr)->realtimeTextReceived(character, call);
|
||||
//L_GET_PRIVATE(static_pointer_cast<LinphonePrivate::RealTimeTextChatRoom>(L_GET_CPP_PTR_FROM_C_OBJECT(cr)))->realtimeTextReceived(character, call);
|
||||
}
|
||||
if (!(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities() & LinphonePrivate::ChatRoom::Capabilities::RealTimeText))
|
||||
return;
|
||||
L_GET_PRIVATE_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->realtimeTextReceived(character, L_GET_CPP_PTR_FROM_C_OBJECT(call));
|
||||
}
|
||||
|
||||
unsigned int linphone_chat_message_store(LinphoneChatMessage *msg) {
|
||||
|
|
|
|||
|
|
@ -766,7 +766,7 @@ void linphone_friend_list_synchronize_friends_from_server(LinphoneFriendList *li
|
|||
LinphoneFriend * linphone_friend_list_find_friend_by_address(const LinphoneFriendList *list, const LinphoneAddress *address) {
|
||||
LinphoneAddress *clean_addr = linphone_address_clone(address);
|
||||
LinphoneFriend *lf;
|
||||
if (linphone_address_has_param(clean_addr, "gr")) {
|
||||
if (linphone_address_has_uri_param(clean_addr, "gr")) {
|
||||
linphone_address_remove_uri_param(clean_addr, "gr");
|
||||
}
|
||||
char *uri = linphone_address_as_string_uri_only(clean_addr);
|
||||
|
|
|
|||
|
|
@ -917,7 +917,7 @@ 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 (strstr(username, "chatroom-") == username)
|
||||
if (username && (strstr(username, "chatroom-") == username))
|
||||
return;
|
||||
// End of workaround
|
||||
|
||||
|
|
|
|||
|
|
@ -355,7 +355,6 @@ LinphoneChatMessageStateChangedCb linphone_chat_message_get_message_state_change
|
|||
void linphone_chat_message_set_message_state_changed_cb(LinphoneChatMessage* msg, LinphoneChatMessageStateChangedCb cb);
|
||||
void linphone_chat_message_set_message_state_changed_cb_user_data(LinphoneChatMessage* msg, void *user_data);
|
||||
void * linphone_chat_message_get_message_state_changed_cb_user_data(LinphoneChatMessage* msg);
|
||||
void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state);
|
||||
LinphoneChatRoom *_linphone_core_create_chat_room_from_call(LinphoneCall *call);
|
||||
|
||||
void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id);
|
||||
|
|
|
|||
|
|
@ -151,11 +151,6 @@ struct _LinphoneAuthInfo
|
|||
char *algorithm;
|
||||
};
|
||||
|
||||
struct _LinphoneChatMessageCharacter {
|
||||
uint32_t value;
|
||||
bool_t has_been_read;
|
||||
};
|
||||
|
||||
struct _LinphoneFriendPresence {
|
||||
char *uri_or_tel;
|
||||
LinphonePresenceModel *presence;
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ typedef struct StunCandidate StunCandidate;
|
|||
|
||||
typedef struct _PortConfig PortConfig;
|
||||
|
||||
typedef struct _LinphoneChatMessageCharacter LinphoneChatMessageCharacter;
|
||||
|
||||
typedef struct _LinphoneFriendPresence LinphoneFriendPresence;
|
||||
|
||||
typedef struct _LinphoneFriendPhoneNumberSipUri LinphoneFriendPhoneNumberSipUri;
|
||||
|
|
|
|||
|
|
@ -249,6 +249,13 @@ typedef void (*LinphoneChatRoomCbsParticipantDeviceFetchedCb) (LinphoneChatRoom
|
|||
*/
|
||||
typedef void (*LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb) (LinphoneChatRoom *cr, const LinphoneAddress *deviceAddr, const bctbx_list_t *participantsAddr);
|
||||
|
||||
/**
|
||||
* Callback used to tell the core whether or not to store the incoming message in db or not using linphone_chat_message_set_to_be_stored().
|
||||
* @param[in] cr #LinphoneChatRoom object
|
||||
* @param[in] msg The #LinphoneChatMessage that is being received
|
||||
*/
|
||||
typedef void (*LinphoneChatRoomCbsShouldChatMessageBeStoredCb) (LinphoneChatRoom *cr, LinphoneChatMessage *msg);
|
||||
|
||||
/**
|
||||
* @}
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -271,6 +271,19 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb linphone_ch
|
|||
*/
|
||||
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_participants_capabilities_checked (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb cb);
|
||||
|
||||
/**
|
||||
* Get the message should be stored callback.
|
||||
* @param[in] cbs LinphoneChatRoomCbs object
|
||||
* @return The message should be stored getting callback
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneChatRoomCbsShouldChatMessageBeStoredCb linphone_chat_room_cbs_get_chat_message_should_be_stored( LinphoneChatRoomCbs *cbs);
|
||||
/**
|
||||
* Set the message should be stored callback.
|
||||
* @param[in] cbs LinphoneChatRoomCbs object
|
||||
* @param[in] cb The message should be stored callback to be used
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_chat_message_should_be_stored( LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsShouldChatMessageBeStoredCb cb);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -179,6 +179,23 @@ LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *
|
|||
*/
|
||||
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int begin, int end);
|
||||
|
||||
/**
|
||||
* Gets nb_events most recent chat message events from cr chat room, sorted from oldest to most recent.
|
||||
* @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which events should be retrieved
|
||||
* @param[in] nb_events Number of events to retrieve. 0 means everything.
|
||||
* @return \bctbx_list{LinphoneEventLog}
|
||||
*/
|
||||
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_message_events (LinphoneChatRoom *cr, int nb_events);
|
||||
|
||||
/**
|
||||
* Gets the partial list of chat message events in the given range, sorted from oldest to most recent.
|
||||
* @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which events should be retrieved
|
||||
* @param[in] begin The first event of the range to be retrieved. History most recent event has index 0.
|
||||
* @param[in] end The last event of the range to be retrieved. History oldest event has index of history size - 1
|
||||
* @return \bctbx_list{LinphoneEventLog}
|
||||
*/
|
||||
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_room_get_history_range_message_events (LinphoneChatRoom *cr, int begin, int end);
|
||||
|
||||
/**
|
||||
* Gets nb_events most recent events from cr chat room, sorted from oldest to most recent.
|
||||
* @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which events should be retrieved
|
||||
|
|
@ -281,6 +298,13 @@ LINPHONE_PUBLIC LinphoneChatRoomState linphone_chat_room_get_state (const Linpho
|
|||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_chat_room_has_been_left (const LinphoneChatRoom *cr);
|
||||
|
||||
/**
|
||||
* Return the last updated time for the chat room
|
||||
* @param[in] cr LinphoneChatRoom object
|
||||
* @return the last updated time
|
||||
*/
|
||||
LINPHONE_PUBLIC time_t linphone_chat_room_get_last_update_time(const LinphoneChatRoom *cr);
|
||||
|
||||
/**
|
||||
* Add a participant to a chat room. This may fail if this type of chat room does not handle participants.
|
||||
* Use linphone_chat_room_can_handle_participants() to know if this chat room handles participants.
|
||||
|
|
|
|||
|
|
@ -90,12 +90,19 @@ LINPHONE_PUBLIC float linphone_call_log_get_quality(const LinphoneCallLog *cl);
|
|||
**/
|
||||
LINPHONE_PUBLIC const char * linphone_call_log_get_ref_key(const LinphoneCallLog *cl);
|
||||
|
||||
/**
|
||||
* Get the local address (that is from or to depending on call direction)
|
||||
* @param[in] cl LinphoneCallLog object
|
||||
* @return The local address of the call
|
||||
*/
|
||||
LINPHONE_PUBLIC const LinphoneAddress *linphone_call_log_get_local_address(const LinphoneCallLog *cl);
|
||||
|
||||
/**
|
||||
* Get the remote address (that is from or to depending on call direction).
|
||||
* @param[in] cl LinphoneCallLog object
|
||||
* @return The remote address of the call.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneAddress * linphone_call_log_get_remote_address(const LinphoneCallLog *cl);
|
||||
LINPHONE_PUBLIC const LinphoneAddress * linphone_call_log_get_remote_address(const LinphoneCallLog *cl);
|
||||
|
||||
/**
|
||||
* Get the RTP statistics computed by the remote end and sent back via RTCP.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Namespace.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define LINPHONE_BEGIN_NAMESPACE namespace LinphonePrivate {
|
||||
#define LINPHONE_END_NAMESPACE }
|
||||
|
|
@ -75,10 +79,10 @@ LINPHONE_BEGIN_NAMESPACE
|
|||
// Debug.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void l_assert (const char *condition, const char *file, int line);
|
||||
void lAssert (const char *condition, const char *file, int line);
|
||||
|
||||
#ifdef DEBUG
|
||||
#define L_ASSERT(CONDITION) ((CONDITION) ? static_cast<void>(0) : LinphonePrivate::l_assert(#CONDITION, __FILE__, __LINE__))
|
||||
#define L_ASSERT(CONDITION) ((CONDITION) ? static_cast<void>(0) : LinphonePrivate::lAssert(#CONDITION, __FILE__, __LINE__))
|
||||
#else
|
||||
#define L_ASSERT(CONDITION) static_cast<void>(false && (CONDITION))
|
||||
#endif
|
||||
|
|
@ -100,16 +104,26 @@ void l_assert (const char *condition, const char *file, int line);
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Define an integer version like: 0xXXYYZZ, XX=MAJOR, YY=MINOR, and ZZ=PATCH.
|
||||
#define L_VERSION(MAJOR, MINOR, PATCH) (((MAJOR) << 16) | ((MINOR) << 8) | (PATCH))
|
||||
constexpr unsigned int makeVersion (unsigned int major, unsigned int minor, unsigned int patch) {
|
||||
return ((major << 16) | (minor << 8) | patch);
|
||||
}
|
||||
|
||||
// Not available in C++11...
|
||||
template<typename T, typename... Args>
|
||||
std::unique_ptr<T> make_unique(Args && ...args) {
|
||||
std::unique_ptr<T> makeUnique(Args && ...args) {
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Data access.
|
||||
// Class tools.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define L_DISABLE_COPY(CLASS) \
|
||||
CLASS (const CLASS &) = delete; \
|
||||
CLASS &operator= (const CLASS &) = delete;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PImpl tools.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class BaseObject;
|
||||
|
|
@ -119,34 +133,68 @@ class ClonableObjectPrivate;
|
|||
class Object;
|
||||
class ObjectPrivate;
|
||||
|
||||
namespace Private {
|
||||
template<typename T>
|
||||
using BetterPrivateAncestor = typename std::conditional<
|
||||
std::is_base_of<BaseObject, T>::value,
|
||||
BaseObject,
|
||||
typename std::conditional<
|
||||
std::is_base_of<ClonableObject, T>::value,
|
||||
ClonableObject,
|
||||
T
|
||||
>::type
|
||||
>::type;
|
||||
|
||||
// Generic public helper.
|
||||
template<
|
||||
typename R,
|
||||
typename P,
|
||||
typename C
|
||||
>
|
||||
constexpr R *getPublicHelper (P *object, const C *) {
|
||||
return static_cast<R *>(object);
|
||||
}
|
||||
|
||||
// Generic public helper. Deal with shared data.
|
||||
template<
|
||||
typename R,
|
||||
typename P,
|
||||
typename C
|
||||
>
|
||||
inline R *getPublicHelper (const P &objectSet, const C *) {
|
||||
auto it = objectSet.cbegin();
|
||||
L_ASSERT(it != objectSet.cend());
|
||||
return static_cast<R *>(*it);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
struct AddConstMirror {
|
||||
typedef U type;
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct AddConstMirror<const T, U> {
|
||||
typedef typename std::add_const<U>::type type;
|
||||
};
|
||||
}
|
||||
|
||||
#define L_INTERNAL_CHECK_OBJECT_INHERITANCE(CLASS) \
|
||||
static_assert( \
|
||||
!(std::is_base_of<BaseObject, CLASS>::value && std::is_base_of<ClonableObject, CLASS>::value), \
|
||||
"Multiple inheritance between BaseObject and ClonableObject is not allowed." \
|
||||
);
|
||||
|
||||
#define L_INTERNAL_GET_BETTER_PRIVATE_ANCESTOR(CLASS) \
|
||||
std::conditional< \
|
||||
std::is_base_of<BaseObject, CLASS>::value, \
|
||||
BaseObject, \
|
||||
std::conditional< \
|
||||
std::is_base_of<ClonableObject, CLASS>::value, \
|
||||
ClonableObject, \
|
||||
CLASS \
|
||||
>::type \
|
||||
>::type
|
||||
|
||||
#define L_INTERNAL_DECLARE_PRIVATE(CLASS) \
|
||||
inline CLASS ## Private *getPrivate () { \
|
||||
L_INTERNAL_CHECK_OBJECT_INHERITANCE(CLASS); \
|
||||
return reinterpret_cast<CLASS ## Private *>( \
|
||||
L_INTERNAL_GET_BETTER_PRIVATE_ANCESTOR(CLASS)::mPrivate \
|
||||
LinphonePrivate::Private::BetterPrivateAncestor<CLASS>::mPrivate \
|
||||
); \
|
||||
} \
|
||||
inline const CLASS ## Private *getPrivate () const { \
|
||||
L_INTERNAL_CHECK_OBJECT_INHERITANCE(CLASS); \
|
||||
return reinterpret_cast<const CLASS ## Private *>( \
|
||||
L_INTERNAL_GET_BETTER_PRIVATE_ANCESTOR(CLASS)::mPrivate \
|
||||
LinphonePrivate::Private::BetterPrivateAncestor<CLASS>::mPrivate \
|
||||
); \
|
||||
} \
|
||||
friend class CLASS ## Private; \
|
||||
|
|
@ -162,61 +210,25 @@ class ObjectPrivate;
|
|||
friend class Tester;
|
||||
#endif
|
||||
|
||||
// Generic public helper.
|
||||
template<
|
||||
typename R,
|
||||
typename P,
|
||||
typename C
|
||||
>
|
||||
constexpr R *getPublicHelper (P *object, const C *) {
|
||||
return static_cast<R *>(object);
|
||||
}
|
||||
|
||||
// Generic public helper. Deal with shared data.
|
||||
template<
|
||||
typename R,
|
||||
typename P,
|
||||
typename C
|
||||
>
|
||||
inline R *getPublicHelper (const P &objectSet, const C *) {
|
||||
auto it = objectSet.cbegin();
|
||||
L_ASSERT(it != objectSet.cend());
|
||||
return static_cast<R *>(*it);
|
||||
}
|
||||
|
||||
#define L_DECLARE_PUBLIC(CLASS) \
|
||||
inline CLASS *getPublic () { \
|
||||
return getPublicHelper<CLASS>(mPublic, this); \
|
||||
CLASS *getPublic () { \
|
||||
return LinphonePrivate::Private::getPublicHelper<CLASS>(mPublic, this); \
|
||||
} \
|
||||
inline const CLASS *getPublic () const { \
|
||||
return getPublicHelper<const CLASS>(mPublic, this); \
|
||||
const CLASS *getPublic () const { \
|
||||
return LinphonePrivate::Private::getPublicHelper<const CLASS>(mPublic, this); \
|
||||
} \
|
||||
friend class CLASS;
|
||||
|
||||
#define L_DISABLE_COPY(CLASS) \
|
||||
CLASS (const CLASS &) = delete; \
|
||||
CLASS &operator= (const CLASS &) = delete;
|
||||
|
||||
// Get Private data.
|
||||
#define L_D() decltype(getPrivate()) const d = getPrivate();
|
||||
|
||||
// Get Public data.
|
||||
#define L_Q() decltype(getPublic()) const q = getPublic();
|
||||
|
||||
template<typename T, typename U>
|
||||
struct AddConstMirror {
|
||||
typedef U type;
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct AddConstMirror<const T, U> {
|
||||
typedef typename std::add_const<U>::type type;
|
||||
};
|
||||
|
||||
// Get Private data of class in a multiple inheritance case.
|
||||
#define L_D_T(CLASS, NAME) \
|
||||
auto const NAME = static_cast< \
|
||||
AddConstMirror< \
|
||||
LinphonePrivate::Private::AddConstMirror< \
|
||||
std::remove_reference<decltype(*this)>::type, \
|
||||
CLASS ## Private \
|
||||
>::type * \
|
||||
|
|
@ -225,12 +237,16 @@ struct AddConstMirror<const T, U> {
|
|||
// Get Private data of class in a multiple inheritance case.
|
||||
#define L_Q_T(CLASS, NAME) \
|
||||
auto const NAME = static_cast< \
|
||||
AddConstMirror< \
|
||||
LinphonePrivate::Private::AddConstMirror< \
|
||||
std::remove_reference<decltype(*this)>::type, \
|
||||
CLASS \
|
||||
>::type * \
|
||||
>(getPublic());
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Overload.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define L_OVERRIDE_SHARED_FROM_THIS(CLASS) \
|
||||
inline std::shared_ptr<CLASS> getSharedFromThis () { \
|
||||
return std::static_pointer_cast<CLASS>(Object::getSharedFromThis()); \
|
||||
|
|
@ -239,10 +255,6 @@ struct AddConstMirror<const T, U> {
|
|||
return std::static_pointer_cast<const CLASS>(Object::getSharedFromThis()); \
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Overload.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace Private {
|
||||
template<typename... Args>
|
||||
struct ResolveMemberFunctionOverload {
|
||||
|
|
@ -273,7 +285,8 @@ namespace Private {
|
|||
}
|
||||
|
||||
// Useful to select a specific overloaded function. (Avoid usage of static_cast.)
|
||||
#define L_RESOLVE_OVERLOAD(ARGS) LinphonePrivate::Private::ResolveOverload<ARGS>
|
||||
template<typename... Args>
|
||||
using resolveOverload = Private::ResolveOverload<Args...>;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Wrapper public.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "call/call.h"
|
||||
#include "call/local-conference-call.h"
|
||||
#include "call/remote-conference-call.h"
|
||||
#include "chat/chat-room/real-time-text-chat-room.h"
|
||||
#include "conference/params/media-session-params-p.h"
|
||||
#include "core/core-p.h"
|
||||
|
||||
|
|
@ -246,7 +247,7 @@ const char *linphone_call_get_to_header (const LinphoneCall *call, const char *n
|
|||
}
|
||||
|
||||
char *linphone_call_get_remote_address_as_string (const LinphoneCall *call) {
|
||||
return ms_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteAddressAsString().c_str());
|
||||
return ms_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteAddress().asString().c_str());
|
||||
}
|
||||
|
||||
const LinphoneAddress *linphone_call_get_diversion_address (const LinphoneCall *call) {
|
||||
|
|
@ -538,16 +539,10 @@ bool_t linphone_call_echo_limiter_enabled (const LinphoneCall *call) {
|
|||
}
|
||||
|
||||
LinphoneChatRoom *linphone_call_get_chat_room (LinphoneCall *call) {
|
||||
#if 0
|
||||
if (!call->chat_room){
|
||||
if (call->state != LinphoneCallReleased && call->state != LinphoneCallEnd){
|
||||
call->chat_room = _linphone_core_create_chat_room_from_call(call);
|
||||
}
|
||||
}
|
||||
return call->chat_room;
|
||||
#else
|
||||
shared_ptr<LinphonePrivate::RealTimeTextChatRoom> acr = L_GET_PRIVATE_FROM_C_OBJECT(call)->getChatRoom();
|
||||
if (acr)
|
||||
return L_GET_C_BACK_PTR(acr);
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
float linphone_call_get_play_volume (const LinphoneCall *call) {
|
||||
|
|
|
|||
|
|
@ -209,10 +209,6 @@ void linphone_chat_message_resend_2(LinphoneChatMessage *msg) {
|
|||
L_GET_CPP_PTR_FROM_C_OBJECT(msg)->send();
|
||||
}
|
||||
|
||||
void linphone_chat_message_update_state(LinphoneChatMessage *msg, LinphoneChatMessageState new_state) {
|
||||
L_GET_CPP_PTR_FROM_C_OBJECT(msg)->updateState((LinphonePrivate::ChatMessage::State) new_state);
|
||||
}
|
||||
|
||||
LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg, uint32_t character) {
|
||||
return ((LinphoneStatus)L_GET_CPP_PTR_FROM_C_OBJECT(msg)->putCharacter(character));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ struct _LinphoneChatRoomCbs {
|
|||
LinphoneChatRoomCbsConferenceAddressGenerationCb conferenceAddressGenerationCb;
|
||||
LinphoneChatRoomCbsParticipantDeviceFetchedCb participantDeviceFetchedCb;
|
||||
LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb participantsCapabilitiesChecked;
|
||||
LinphoneChatRoomCbsShouldChatMessageBeStoredCb shouldMessageBeStoredCb;
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatRoomCbs);
|
||||
|
|
@ -196,3 +197,11 @@ LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb linphone_chat_room_cbs_get_
|
|||
void linphone_chat_room_cbs_set_participants_capabilities_checked (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsParticipantsCapabilitiesCheckedCb cb) {
|
||||
cbs->participantsCapabilitiesChecked = cb;
|
||||
}
|
||||
|
||||
LinphoneChatRoomCbsShouldChatMessageBeStoredCb linphone_chat_room_cbs_get_chat_message_should_be_stored( LinphoneChatRoomCbs *cbs) {
|
||||
return cbs->shouldMessageBeStoredCb;
|
||||
}
|
||||
|
||||
void linphone_chat_room_cbs_set_chat_message_should_be_stored( LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsShouldChatMessageBeStoredCb cb) {
|
||||
cbs->shouldMessageBeStoredCb = cb;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "address/identity-address.h"
|
||||
#include "c-wrapper/c-wrapper.h"
|
||||
#include "call/call.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-p.h"
|
||||
|
|
@ -156,9 +157,9 @@ void linphone_chat_room_receive_chat_message (LinphoneChatRoom *cr, LinphoneChat
|
|||
}
|
||||
|
||||
uint32_t linphone_chat_room_get_char (const LinphoneChatRoom *cr) {
|
||||
if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr)))
|
||||
return L_GET_CPP_PTR_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->getChar();
|
||||
return 0;
|
||||
if (!(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities() & LinphonePrivate::ChatRoom::Capabilities::RealTimeText))
|
||||
return 0;
|
||||
return L_GET_CPP_PTR_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->getChar();
|
||||
}
|
||||
|
||||
void linphone_chat_room_compose (LinphoneChatRoom *cr) {
|
||||
|
|
@ -166,14 +167,15 @@ void linphone_chat_room_compose (LinphoneChatRoom *cr) {
|
|||
}
|
||||
|
||||
LinphoneCall *linphone_chat_room_get_call (const LinphoneChatRoom *cr) {
|
||||
if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr)))
|
||||
return L_GET_CPP_PTR_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->getCall();
|
||||
return nullptr;
|
||||
if (!(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities() & LinphonePrivate::ChatRoom::Capabilities::RealTimeText))
|
||||
return nullptr;
|
||||
return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->getCall());
|
||||
}
|
||||
|
||||
void linphone_chat_room_set_call (LinphoneChatRoom *cr, LinphoneCall *call) {
|
||||
if (linphone_core_realtime_text_enabled(linphone_chat_room_get_core(cr)))
|
||||
L_GET_PRIVATE_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->call = call;
|
||||
if (!(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getCapabilities() & LinphonePrivate::ChatRoom::Capabilities::RealTimeText))
|
||||
return;
|
||||
L_GET_PRIVATE_FROM_C_OBJECT(cr, RealTimeTextChatRoom)->call = L_GET_CPP_PTR_FROM_C_OBJECT(call);
|
||||
}
|
||||
|
||||
void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) {
|
||||
|
|
@ -202,9 +204,8 @@ void linphone_chat_room_delete_history (LinphoneChatRoom *cr) {
|
|||
|
||||
bctbx_list_t *linphone_chat_room_get_history_range (LinphoneChatRoom *cr, int startm, int endm) {
|
||||
list<shared_ptr<LinphonePrivate::ChatMessage>> chatMessages;
|
||||
for (auto &event : L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistoryRange(startm, endm))
|
||||
if (event->getType() == LinphonePrivate::EventLog::Type::ConferenceChatMessage)
|
||||
chatMessages.push_back(static_pointer_cast<LinphonePrivate::ConferenceChatMessageEvent>(event)->getChatMessage());
|
||||
for (auto &event : L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getMessageHistoryRange(startm, endm))
|
||||
chatMessages.push_back(static_pointer_cast<LinphonePrivate::ConferenceChatMessageEvent>(event)->getChatMessage());
|
||||
|
||||
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(chatMessages);
|
||||
}
|
||||
|
|
@ -213,6 +214,14 @@ bctbx_list_t *linphone_chat_room_get_history (LinphoneChatRoom *cr, int nb_messa
|
|||
return linphone_chat_room_get_history_range(cr, 0, nb_message);
|
||||
}
|
||||
|
||||
bctbx_list_t *linphone_chat_room_get_history_range_message_events (LinphoneChatRoom *cr, int startm, int endm) {
|
||||
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getMessageHistoryRange(startm, endm));
|
||||
}
|
||||
|
||||
bctbx_list_t *linphone_chat_room_get_history_message_events (LinphoneChatRoom *cr, int nb_events) {
|
||||
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getMessageHistory(nb_events));
|
||||
}
|
||||
|
||||
bctbx_list_t *linphone_chat_room_get_history_events (LinphoneChatRoom *cr, int nb_events) {
|
||||
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getHistory(nb_events));
|
||||
}
|
||||
|
|
@ -251,6 +260,10 @@ bool_t linphone_chat_room_has_been_left (const LinphoneChatRoom *cr) {
|
|||
return (bool_t)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->hasBeenLeft();
|
||||
}
|
||||
|
||||
time_t linphone_chat_room_get_last_update_time(const LinphoneChatRoom *cr) {
|
||||
return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getLastUpdateTime();
|
||||
}
|
||||
|
||||
void linphone_chat_room_add_participant (LinphoneChatRoom *cr, const LinphoneAddress *addr) {
|
||||
L_GET_CPP_PTR_FROM_C_OBJECT(cr)->addParticipant(
|
||||
LinphonePrivate::IdentityAddress(*L_GET_CPP_PTR_FROM_C_OBJECT(addr)), nullptr, false
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ public:
|
|||
typename = typename std::enable_if<IsDefinedBaseCppObject<CppType>::value, CppType>::type
|
||||
>
|
||||
static inline std::shared_ptr<const CppType> getCppPtrFromC (const CType *cObject) {
|
||||
return getCppPtrFromC<CType, CppType>(const_cast<CType *>(cObject));
|
||||
return getCppPtrFromC<typename std::remove_const<CType>::type, CppType>(const_cast<CType *>(cObject));
|
||||
}
|
||||
|
||||
template<
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
class CallSession;
|
||||
class RealTimeTextChatRoom;
|
||||
|
||||
class CallPrivate : public ObjectPrivate, public CallSessionListener {
|
||||
public:
|
||||
|
|
@ -50,6 +51,7 @@ public:
|
|||
|
||||
virtual std::shared_ptr<CallSession> getActiveSession () const { return nullptr; }
|
||||
bool getAudioMuted () const;
|
||||
std::shared_ptr<RealTimeTextChatRoom> getChatRoom ();
|
||||
|
||||
LinphoneProxyConfig *getDestProxy () const;
|
||||
IceSession *getIceSession () const;
|
||||
|
|
@ -72,43 +74,44 @@ private:
|
|||
void terminateBecauseOfLostMedia ();
|
||||
|
||||
/* CallSessionListener */
|
||||
void onAckBeingSent (const std::shared_ptr<const CallSession> &session, LinphoneHeaders *headers) override;
|
||||
void onAckReceived (const std::shared_ptr<const CallSession> &session, LinphoneHeaders *headers) override;
|
||||
void onBackgroundTaskToBeStarted (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onBackgroundTaskToBeStopped (const std::shared_ptr<const CallSession> &session) override;
|
||||
bool onCallSessionAccepted (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onCallSessionConferenceStreamStarting (const std::shared_ptr<const CallSession> &session, bool mute) override;
|
||||
void onCallSessionConferenceStreamStopping (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onCallSessionEarlyFailed (const std::shared_ptr<const CallSession> &session, LinphoneErrorInfo *ei) override;
|
||||
void onCallSessionSetReleased (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onCallSessionSetTerminated (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onCallSessionStartReferred (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onCallSessionStateChanged (const std::shared_ptr<const CallSession> &session, CallSession::State state, const std::string &message) override;
|
||||
void onCallSessionTransferStateChanged (const std::shared_ptr<const CallSession> &session, CallSession::State state) override;
|
||||
void onCheckForAcceptation (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onDtmfReceived (const std::shared_ptr<const CallSession> &session, char dtmf) override;
|
||||
void onIncomingCallSessionNotified (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onIncomingCallSessionStarted (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onIncomingCallSessionTimeoutCheck (const std::shared_ptr<const CallSession> &session, int elapsed, bool oneSecondElapsed) override;
|
||||
void onInfoReceived (const std::shared_ptr<const CallSession> &session, const LinphoneInfoMessage *im) override;
|
||||
void onNoMediaTimeoutCheck (const std::shared_ptr<const CallSession> &session, bool oneSecondElapsed) override;
|
||||
void onEncryptionChanged (const std::shared_ptr<const CallSession> &session, bool activated, const std::string &authToken) override;
|
||||
void onCallSessionStateChangedForReporting (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onRtcpUpdateForReporting (const std::shared_ptr<const CallSession> &session, SalStreamType type) override;
|
||||
void onStatsUpdated (const std::shared_ptr<const CallSession> &session, const LinphoneCallStats *stats) override;
|
||||
void onUpdateMediaInfoForReporting (const std::shared_ptr<const CallSession> &session, int statsType) override;
|
||||
void onResetCurrentSession (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onSetCurrentSession (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onFirstVideoFrameDecoded (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onResetFirstVideoFrameDecoded (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onPlayErrorTone (const std::shared_ptr<const CallSession> &session, LinphoneReason reason) override;
|
||||
void onRingbackToneRequested (const std::shared_ptr<const CallSession> &session, bool requested) override;
|
||||
void onStartRinging (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onStopRinging (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onStopRingingIfInCall (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onStopRingingIfNeeded (const std::shared_ptr<const CallSession> &session) override;
|
||||
bool areSoundResourcesAvailable (const std::shared_ptr<const CallSession> &session) override;
|
||||
bool isPlayingRingbackTone (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onAckBeingSent (const std::shared_ptr<CallSession> &session, LinphoneHeaders *headers) override;
|
||||
void onAckReceived (const std::shared_ptr<CallSession> &session, LinphoneHeaders *headers) override;
|
||||
void onBackgroundTaskToBeStarted (const std::shared_ptr<CallSession> &session) override;
|
||||
void onBackgroundTaskToBeStopped (const std::shared_ptr<CallSession> &session) override;
|
||||
bool onCallSessionAccepted (const std::shared_ptr<CallSession> &session) override;
|
||||
void onCallSessionConferenceStreamStarting (const std::shared_ptr<CallSession> &session, bool mute) override;
|
||||
void onCallSessionConferenceStreamStopping (const std::shared_ptr<CallSession> &session) override;
|
||||
void onCallSessionEarlyFailed (const std::shared_ptr<CallSession> &session, LinphoneErrorInfo *ei) override;
|
||||
void onCallSessionSetReleased (const std::shared_ptr<CallSession> &session) override;
|
||||
void onCallSessionSetTerminated (const std::shared_ptr<CallSession> &session) override;
|
||||
void onCallSessionStartReferred (const std::shared_ptr<CallSession> &session) override;
|
||||
void onCallSessionStateChanged (const std::shared_ptr<CallSession> &session, CallSession::State state, const std::string &message) override;
|
||||
void onCallSessionTransferStateChanged (const std::shared_ptr<CallSession> &session, CallSession::State state) override;
|
||||
void onCheckForAcceptation (const std::shared_ptr<CallSession> &session) override;
|
||||
void onDtmfReceived (const std::shared_ptr<CallSession> &session, char dtmf) override;
|
||||
void onIncomingCallSessionNotified (const std::shared_ptr<CallSession> &session) override;
|
||||
void onIncomingCallSessionStarted (const std::shared_ptr<CallSession> &session) override;
|
||||
void onIncomingCallSessionTimeoutCheck (const std::shared_ptr<CallSession> &session, int elapsed, bool oneSecondElapsed) override;
|
||||
void onInfoReceived (const std::shared_ptr<CallSession> &session, const LinphoneInfoMessage *im) override;
|
||||
void onNoMediaTimeoutCheck (const std::shared_ptr<CallSession> &session, bool oneSecondElapsed) override;
|
||||
void onEncryptionChanged (const std::shared_ptr<CallSession> &session, bool activated, const std::string &authToken) override;
|
||||
void onCallSessionStateChangedForReporting (const std::shared_ptr<CallSession> &session) override;
|
||||
void onRtcpUpdateForReporting (const std::shared_ptr<CallSession> &session, SalStreamType type) override;
|
||||
void onStatsUpdated (const std::shared_ptr<CallSession> &session, const LinphoneCallStats *stats) override;
|
||||
void onUpdateMediaInfoForReporting (const std::shared_ptr<CallSession> &session, int statsType) override;
|
||||
void onResetCurrentSession (const std::shared_ptr<CallSession> &session) override;
|
||||
void onSetCurrentSession (const std::shared_ptr<CallSession> &session) override;
|
||||
void onFirstVideoFrameDecoded (const std::shared_ptr<CallSession> &session) override;
|
||||
void onResetFirstVideoFrameDecoded (const std::shared_ptr<CallSession> &session) override;
|
||||
void onPlayErrorTone (const std::shared_ptr<CallSession> &session, LinphoneReason reason) override;
|
||||
void onRingbackToneRequested (const std::shared_ptr<CallSession> &session, bool requested) override;
|
||||
void onStartRinging (const std::shared_ptr<CallSession> &session) override;
|
||||
void onStopRinging (const std::shared_ptr<CallSession> &session) override;
|
||||
void onStopRingingIfInCall (const std::shared_ptr<CallSession> &session) override;
|
||||
void onStopRingingIfNeeded (const std::shared_ptr<CallSession> &session) override;
|
||||
bool areSoundResourcesAvailable (const std::shared_ptr<CallSession> &session) override;
|
||||
bool isPlayingRingbackTone (const std::shared_ptr<CallSession> &session) override;
|
||||
void onRealTimeTextCharacterReceived (const std::shared_ptr<CallSession> &session, RealtimeTextReceivedCharacter *character) override;
|
||||
|
||||
mutable LinphonePlayer *player = nullptr;
|
||||
|
||||
|
|
@ -119,6 +122,8 @@ private:
|
|||
|
||||
BackgroundTask bgTask;
|
||||
|
||||
mutable std::shared_ptr<RealTimeTextChatRoom> chatRoom;
|
||||
|
||||
L_DECLARE_PUBLIC(Call);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "c-wrapper/c-wrapper.h"
|
||||
#include "call-p.h"
|
||||
#include "chat/chat-room/real-time-text-chat-room-p.h"
|
||||
#include "conference/params/media-session-params-p.h"
|
||||
#include "conference/session/call-session-p.h"
|
||||
#include "conference/session/media-session-p.h"
|
||||
|
|
@ -37,6 +38,17 @@ bool CallPrivate::getAudioMuted () const {
|
|||
return static_pointer_cast<MediaSession>(getActiveSession())->getPrivate()->getAudioMuted();
|
||||
}
|
||||
|
||||
shared_ptr<RealTimeTextChatRoom> CallPrivate::getChatRoom () {
|
||||
L_Q();
|
||||
if (!chatRoom && (q->getState() != CallSession::State::End) && (q->getState() != CallSession::State::Released)) {
|
||||
ChatRoomId chatRoomId(q->getRemoteAddress(), q->getLocalAddress());
|
||||
RealTimeTextChatRoom *rttcr = new RealTimeTextChatRoom(q->getCore(), chatRoomId);
|
||||
chatRoom.reset(rttcr);
|
||||
rttcr->getPrivate()->setCall(q->getSharedFromThis());
|
||||
}
|
||||
return chatRoom;
|
||||
}
|
||||
|
||||
LinphoneProxyConfig *CallPrivate::getDestProxy () const {
|
||||
return getActiveSession()->getPrivate()->getDestProxy();
|
||||
}
|
||||
|
|
@ -167,7 +179,7 @@ void CallPrivate::startRemoteRing () {
|
|||
|
||||
void CallPrivate::terminateBecauseOfLostMedia () {
|
||||
L_Q();
|
||||
lInfo() << "Call [" << q << "]: Media connectivity with " << q->getRemoteAddressAsString()
|
||||
lInfo() << "Call [" << q << "]: Media connectivity with " << q->getRemoteAddress().asString()
|
||||
<< " is lost, call is going to be terminated";
|
||||
static_pointer_cast<MediaSession>(getActiveSession())->terminateBecauseOfLostMedia();
|
||||
linphone_core_play_named_tone(q->getCore()->getCCore(), LinphoneToneCallLost);
|
||||
|
|
@ -175,25 +187,25 @@ void CallPrivate::terminateBecauseOfLostMedia () {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void CallPrivate::onAckBeingSent (const shared_ptr<const CallSession> &session, LinphoneHeaders *headers) {
|
||||
void CallPrivate::onAckBeingSent (const shared_ptr<CallSession> &session, LinphoneHeaders *headers) {
|
||||
L_Q();
|
||||
linphone_call_notify_ack_processing(L_GET_C_BACK_PTR(q), headers, false);
|
||||
}
|
||||
|
||||
void CallPrivate::onAckReceived (const shared_ptr<const CallSession> &session, LinphoneHeaders *headers) {
|
||||
void CallPrivate::onAckReceived (const shared_ptr<CallSession> &session, LinphoneHeaders *headers) {
|
||||
L_Q();
|
||||
linphone_call_notify_ack_processing(L_GET_C_BACK_PTR(q), headers, true);
|
||||
}
|
||||
|
||||
void CallPrivate::onBackgroundTaskToBeStarted (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onBackgroundTaskToBeStarted (const shared_ptr<CallSession> &session) {
|
||||
bgTask.start();
|
||||
}
|
||||
|
||||
void CallPrivate::onBackgroundTaskToBeStopped (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onBackgroundTaskToBeStopped (const shared_ptr<CallSession> &session) {
|
||||
bgTask.stop();
|
||||
}
|
||||
|
||||
bool CallPrivate::onCallSessionAccepted (const shared_ptr<const CallSession> &session) {
|
||||
bool CallPrivate::onCallSessionAccepted (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
LinphoneCore *lc = q->getCore()->getCCore();
|
||||
bool wasRinging = false;
|
||||
|
|
@ -214,21 +226,21 @@ bool CallPrivate::onCallSessionAccepted (const shared_ptr<const CallSession> &se
|
|||
return wasRinging;
|
||||
}
|
||||
|
||||
void CallPrivate::onCallSessionConferenceStreamStarting (const shared_ptr<const CallSession> &session, bool mute) {
|
||||
void CallPrivate::onCallSessionConferenceStreamStarting (const shared_ptr<CallSession> &session, bool mute) {
|
||||
L_Q();
|
||||
if (q->getCore()->getCCore()->conf_ctx) {
|
||||
linphone_conference_on_call_stream_starting(q->getCore()->getCCore()->conf_ctx, L_GET_C_BACK_PTR(q), mute);
|
||||
}
|
||||
}
|
||||
|
||||
void CallPrivate::onCallSessionConferenceStreamStopping (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onCallSessionConferenceStreamStopping (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
LinphoneCore *lc = q->getCore()->getCCore();
|
||||
if (lc->conf_ctx && _linphone_call_get_endpoint(L_GET_C_BACK_PTR(q)))
|
||||
linphone_conference_on_call_stream_stopping(lc->conf_ctx, L_GET_C_BACK_PTR(q));
|
||||
}
|
||||
|
||||
void CallPrivate::onCallSessionEarlyFailed (const shared_ptr<const CallSession> &session, LinphoneErrorInfo *ei) {
|
||||
void CallPrivate::onCallSessionEarlyFailed (const shared_ptr<CallSession> &session, LinphoneErrorInfo *ei) {
|
||||
L_Q();
|
||||
LinphoneCallLog *log = session->getLog();
|
||||
linphone_core_report_early_failed_call(q->getCore()->getCCore(),
|
||||
|
|
@ -239,12 +251,12 @@ void CallPrivate::onCallSessionEarlyFailed (const shared_ptr<const CallSession>
|
|||
linphone_call_unref(L_GET_C_BACK_PTR(q));
|
||||
}
|
||||
|
||||
void CallPrivate::onCallSessionSetReleased (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onCallSessionSetReleased (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
linphone_call_unref(L_GET_C_BACK_PTR(q));
|
||||
}
|
||||
|
||||
void CallPrivate::onCallSessionSetTerminated (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onCallSessionSetTerminated (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
LinphoneCore *core = q->getCore()->getCCore();
|
||||
if (q->getSharedFromThis() == q->getCore()->getCurrentCall()) {
|
||||
|
|
@ -267,21 +279,21 @@ void CallPrivate::onCallSessionSetTerminated (const shared_ptr<const CallSession
|
|||
ms_bandwidth_controller_reset_state(core->bw_controller);
|
||||
}
|
||||
|
||||
void CallPrivate::onCallSessionStartReferred (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onCallSessionStartReferred (const shared_ptr<CallSession> &session) {
|
||||
startReferredCall(nullptr);
|
||||
}
|
||||
|
||||
void CallPrivate::onCallSessionStateChanged (const shared_ptr<const CallSession> &session, CallSession::State state, const string &message) {
|
||||
void CallPrivate::onCallSessionStateChanged (const shared_ptr<CallSession> &session, CallSession::State state, const string &message) {
|
||||
L_Q();
|
||||
linphone_call_notify_state_changed(L_GET_C_BACK_PTR(q), static_cast<LinphoneCallState>(state), message.c_str());
|
||||
}
|
||||
|
||||
void CallPrivate::onCallSessionTransferStateChanged (const shared_ptr<const CallSession> &session, CallSession::State state) {
|
||||
void CallPrivate::onCallSessionTransferStateChanged (const shared_ptr<CallSession> &session, CallSession::State state) {
|
||||
L_Q();
|
||||
linphone_call_notify_transfer_state_changed(L_GET_C_BACK_PTR(q), static_cast<LinphoneCallState>(state));
|
||||
}
|
||||
|
||||
void CallPrivate::onCheckForAcceptation (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onCheckForAcceptation (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
LinphoneCall *lcall = L_GET_C_BACK_PTR(q);
|
||||
bctbx_list_t *copy = bctbx_list_copy(linphone_core_get_calls(q->getCore()->getCCore()));
|
||||
|
|
@ -304,23 +316,23 @@ void CallPrivate::onCheckForAcceptation (const shared_ptr<const CallSession> &se
|
|||
bctbx_list_free(copy);
|
||||
}
|
||||
|
||||
void CallPrivate::onDtmfReceived (const shared_ptr<const CallSession> &session, char dtmf) {
|
||||
void CallPrivate::onDtmfReceived (const shared_ptr<CallSession> &session, char dtmf) {
|
||||
L_Q();
|
||||
linphone_call_notify_dtmf_received(L_GET_C_BACK_PTR(q), dtmf);
|
||||
}
|
||||
|
||||
void CallPrivate::onIncomingCallSessionNotified (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onIncomingCallSessionNotified (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
/* The call is acceptable so we can now add it to our list */
|
||||
q->getCore()->getPrivate()->addCall(q->getSharedFromThis());
|
||||
}
|
||||
|
||||
void CallPrivate::onIncomingCallSessionStarted (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onIncomingCallSessionStarted (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
linphone_core_notify_incoming_call(q->getCore()->getCCore(), L_GET_C_BACK_PTR(q));
|
||||
}
|
||||
|
||||
void CallPrivate::onIncomingCallSessionTimeoutCheck (const shared_ptr<const CallSession> &session, int elapsed, bool oneSecondElapsed) {
|
||||
void CallPrivate::onIncomingCallSessionTimeoutCheck (const shared_ptr<CallSession> &session, int elapsed, bool oneSecondElapsed) {
|
||||
L_Q();
|
||||
if (oneSecondElapsed)
|
||||
lInfo() << "Incoming call ringing for " << elapsed << " seconds";
|
||||
|
|
@ -332,12 +344,12 @@ void CallPrivate::onIncomingCallSessionTimeoutCheck (const shared_ptr<const Call
|
|||
}
|
||||
}
|
||||
|
||||
void CallPrivate::onInfoReceived (const shared_ptr<const CallSession> &session, const LinphoneInfoMessage *im) {
|
||||
void CallPrivate::onInfoReceived (const shared_ptr<CallSession> &session, const LinphoneInfoMessage *im) {
|
||||
L_Q();
|
||||
linphone_call_notify_info_message_received(L_GET_C_BACK_PTR(q), im);
|
||||
}
|
||||
|
||||
void CallPrivate::onNoMediaTimeoutCheck (const shared_ptr<const CallSession> &session, bool oneSecondElapsed) {
|
||||
void CallPrivate::onNoMediaTimeoutCheck (const shared_ptr<CallSession> &session, bool oneSecondElapsed) {
|
||||
L_Q();
|
||||
int disconnectTimeout = linphone_core_get_nortp_timeout(q->getCore()->getCCore());
|
||||
bool disconnected = false;
|
||||
|
|
@ -349,42 +361,42 @@ void CallPrivate::onNoMediaTimeoutCheck (const shared_ptr<const CallSession> &se
|
|||
terminateBecauseOfLostMedia();
|
||||
}
|
||||
|
||||
void CallPrivate::onEncryptionChanged (const shared_ptr<const CallSession> &session, bool activated, const string &authToken) {
|
||||
void CallPrivate::onEncryptionChanged (const shared_ptr<CallSession> &session, bool activated, const string &authToken) {
|
||||
L_Q();
|
||||
linphone_call_notify_encryption_changed(L_GET_C_BACK_PTR(q), activated, authToken.empty() ? nullptr : authToken.c_str());
|
||||
}
|
||||
|
||||
void CallPrivate::onCallSessionStateChangedForReporting (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onCallSessionStateChangedForReporting (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
linphone_reporting_call_state_updated(L_GET_C_BACK_PTR(q));
|
||||
}
|
||||
|
||||
void CallPrivate::onRtcpUpdateForReporting (const shared_ptr<const CallSession> &session, SalStreamType type) {
|
||||
void CallPrivate::onRtcpUpdateForReporting (const shared_ptr<CallSession> &session, SalStreamType type) {
|
||||
L_Q();
|
||||
linphone_reporting_on_rtcp_update(L_GET_C_BACK_PTR(q), type);
|
||||
}
|
||||
|
||||
void CallPrivate::onStatsUpdated (const shared_ptr<const CallSession> &session, const LinphoneCallStats *stats) {
|
||||
void CallPrivate::onStatsUpdated (const shared_ptr<CallSession> &session, const LinphoneCallStats *stats) {
|
||||
L_Q();
|
||||
linphone_call_notify_stats_updated(L_GET_C_BACK_PTR(q), stats);
|
||||
}
|
||||
|
||||
void CallPrivate::onUpdateMediaInfoForReporting (const std::shared_ptr<const CallSession> &session, int statsType) {
|
||||
void CallPrivate::onUpdateMediaInfoForReporting (const shared_ptr<CallSession> &session, int statsType) {
|
||||
L_Q();
|
||||
linphone_reporting_update_media_info(L_GET_C_BACK_PTR(q), statsType);
|
||||
}
|
||||
|
||||
void CallPrivate::onResetCurrentSession (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onResetCurrentSession (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
q->getCore()->getPrivate()->setCurrentCall(nullptr);
|
||||
}
|
||||
|
||||
void CallPrivate::onSetCurrentSession (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onSetCurrentSession (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
q->getCore()->getPrivate()->setCurrentCall(q->getSharedFromThis());
|
||||
}
|
||||
|
||||
void CallPrivate::onFirstVideoFrameDecoded (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onFirstVideoFrameDecoded (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
if (nextVideoFrameDecoded._func) {
|
||||
nextVideoFrameDecoded._func(L_GET_C_BACK_PTR(q), nextVideoFrameDecoded._user_data);
|
||||
|
|
@ -393,16 +405,16 @@ void CallPrivate::onFirstVideoFrameDecoded (const shared_ptr<const CallSession>
|
|||
}
|
||||
}
|
||||
|
||||
void CallPrivate::onResetFirstVideoFrameDecoded (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onResetFirstVideoFrameDecoded (const shared_ptr<CallSession> &session) {
|
||||
resetFirstVideoFrameDecoded();
|
||||
}
|
||||
|
||||
void CallPrivate::onPlayErrorTone (const shared_ptr<const CallSession> &session, LinphoneReason reason) {
|
||||
void CallPrivate::onPlayErrorTone (const shared_ptr<CallSession> &session, LinphoneReason reason) {
|
||||
L_Q();
|
||||
linphone_core_play_call_error_tone(q->getCore()->getCCore(), reason);
|
||||
}
|
||||
|
||||
void CallPrivate::onRingbackToneRequested (const shared_ptr<const CallSession> &session, bool requested) {
|
||||
void CallPrivate::onRingbackToneRequested (const shared_ptr<CallSession> &session, bool requested) {
|
||||
L_Q();
|
||||
if (requested && linphone_core_get_remote_ringback_tone(q->getCore()->getCCore()))
|
||||
playingRingbackTone = true;
|
||||
|
|
@ -410,7 +422,7 @@ void CallPrivate::onRingbackToneRequested (const shared_ptr<const CallSession> &
|
|||
playingRingbackTone = false;
|
||||
}
|
||||
|
||||
void CallPrivate::onStartRinging (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onStartRinging (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
LinphoneCore *lc = q->getCore()->getCCore();
|
||||
if (lc->ringstream)
|
||||
|
|
@ -418,12 +430,12 @@ void CallPrivate::onStartRinging (const shared_ptr<const CallSession> &session)
|
|||
startRemoteRing();
|
||||
}
|
||||
|
||||
void CallPrivate::onStopRinging (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onStopRinging (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
linphone_core_stop_ringing(q->getCore()->getCCore());
|
||||
}
|
||||
|
||||
void CallPrivate::onStopRingingIfInCall (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onStopRingingIfInCall (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
LinphoneCore *lc = q->getCore()->getCCore();
|
||||
// We stop the ring only if we have this current call or if we are in call
|
||||
|
|
@ -432,7 +444,7 @@ void CallPrivate::onStopRingingIfInCall (const shared_ptr<const CallSession> &se
|
|||
}
|
||||
}
|
||||
|
||||
void CallPrivate::onStopRingingIfNeeded (const shared_ptr<const CallSession> &session) {
|
||||
void CallPrivate::onStopRingingIfNeeded (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
LinphoneCore *lc = q->getCore()->getCCore();
|
||||
bool stopRinging = true;
|
||||
|
|
@ -448,17 +460,22 @@ void CallPrivate::onStopRingingIfNeeded (const shared_ptr<const CallSession> &se
|
|||
linphone_core_stop_ringing(lc);
|
||||
}
|
||||
|
||||
bool CallPrivate::areSoundResourcesAvailable (const shared_ptr<const CallSession> &session) {
|
||||
bool CallPrivate::areSoundResourcesAvailable (const shared_ptr<CallSession> &session) {
|
||||
L_Q();
|
||||
LinphoneCore *lc = q->getCore()->getCCore();
|
||||
shared_ptr<Call> currentCall = q->getCore()->getCurrentCall();
|
||||
return !linphone_core_is_in_conference(lc) && (!currentCall || (currentCall == q->getSharedFromThis()));
|
||||
}
|
||||
|
||||
bool CallPrivate::isPlayingRingbackTone (const shared_ptr<const CallSession> &session) {
|
||||
bool CallPrivate::isPlayingRingbackTone (const shared_ptr<CallSession> &session) {
|
||||
return playingRingbackTone;
|
||||
}
|
||||
|
||||
void CallPrivate::onRealTimeTextCharacterReceived (const shared_ptr<CallSession> &session, RealtimeTextReceivedCharacter *data) {
|
||||
L_Q();
|
||||
getChatRoom()->getPrivate()->realtimeTextReceived(data->character, q->getSharedFromThis());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
Call::Call (CallPrivate &p, shared_ptr<Core> core) : Object(p), CoreAccessor(core) {
|
||||
|
|
@ -521,7 +538,7 @@ LinphoneStatus Call::pause () {
|
|||
return static_pointer_cast<MediaSession>(d->getActiveSession())->pause();
|
||||
}
|
||||
|
||||
LinphoneStatus Call::redirect (const std::string &redirectUri) {
|
||||
LinphoneStatus Call::redirect (const string &redirectUri) {
|
||||
L_D();
|
||||
return d->getActiveSession()->redirect(redirectUri);
|
||||
}
|
||||
|
|
@ -536,7 +553,7 @@ LinphoneStatus Call::sendDtmf (char dtmf) {
|
|||
return static_pointer_cast<MediaSession>(d->getActiveSession())->sendDtmf(dtmf);
|
||||
}
|
||||
|
||||
LinphoneStatus Call::sendDtmfs (const std::string &dtmfs) {
|
||||
LinphoneStatus Call::sendDtmfs (const string &dtmfs) {
|
||||
L_D();
|
||||
return static_pointer_cast<MediaSession>(d->getActiveSession())->sendDtmfs(dtmfs);
|
||||
}
|
||||
|
|
@ -682,6 +699,11 @@ const LinphoneErrorInfo *Call::getErrorInfo () const {
|
|||
return d->getActiveSession()->getErrorInfo();
|
||||
}
|
||||
|
||||
const Address &Call::getLocalAddress () const {
|
||||
L_D();
|
||||
return d->getActiveSession()->getLocalAddress();
|
||||
}
|
||||
|
||||
LinphoneCallLog *Call::getLog () const {
|
||||
L_D();
|
||||
return d->getActiveSession()->getLog();
|
||||
|
|
@ -756,11 +778,6 @@ const Address &Call::getRemoteAddress () const {
|
|||
return d->getActiveSession()->getRemoteAddress();
|
||||
}
|
||||
|
||||
string Call::getRemoteAddressAsString () const {
|
||||
L_D();
|
||||
return d->getActiveSession()->getRemoteAddressAsString();
|
||||
}
|
||||
|
||||
string Call::getRemoteContact () const {
|
||||
L_D();
|
||||
return d->getActiveSession()->getRemoteContact();
|
||||
|
|
@ -823,7 +840,7 @@ const Address &Call::getToAddress () const {
|
|||
return d->getActiveSession()->getToAddress();
|
||||
}
|
||||
|
||||
string Call::getToHeader (const std::string &name) const {
|
||||
string Call::getToHeader (const string &name) const {
|
||||
L_D();
|
||||
return d->getActiveSession()->getToHeader(name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ class MediaSessionPrivate;
|
|||
|
||||
class Call : public Object, public CoreAccessor {
|
||||
friend class CallSessionPrivate;
|
||||
friend class ChatMessage;
|
||||
friend class CorePrivate;
|
||||
friend class MediaSessionPrivate;
|
||||
|
||||
|
|
@ -85,6 +86,7 @@ public:
|
|||
const Address &getDiversionAddress () const;
|
||||
int getDuration () const;
|
||||
const LinphoneErrorInfo *getErrorInfo () const;
|
||||
const Address &getLocalAddress () const;
|
||||
LinphoneCallLog *getLog () const;
|
||||
RtpTransport *getMetaRtcpTransport (int streamIndex) const;
|
||||
RtpTransport *getMetaRtpTransport (int streamIndex) const;
|
||||
|
|
@ -98,7 +100,6 @@ public:
|
|||
std::shared_ptr<Call> getReferer () const;
|
||||
std::string getReferTo () const;
|
||||
const Address &getRemoteAddress () const;
|
||||
std::string getRemoteAddressAsString () const;
|
||||
std::string getRemoteContact () const;
|
||||
const MediaSessionParams *getRemoteParams () const;
|
||||
std::string getRemoteUserAgent () const;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ public:
|
|||
|
||||
void setDirection (ChatMessage::Direction dir);
|
||||
|
||||
void setState (ChatMessage::State state, bool force = false);
|
||||
void setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState);
|
||||
void setState (ChatMessage::State newState, bool force = false);
|
||||
|
||||
void setTime (time_t time);
|
||||
|
||||
|
|
@ -134,6 +135,8 @@ public:
|
|||
void updateInDb ();
|
||||
|
||||
private:
|
||||
static bool validStateTransition (ChatMessage::State currentState, ChatMessage::State newState);
|
||||
|
||||
// TODO: Clean attributes.
|
||||
time_t time = ::ms_time(0); // TODO: Change me in all files.
|
||||
std::string imdnId;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include "address/address.h"
|
||||
#include "c-wrapper/c-wrapper.h"
|
||||
#include "call/call.h"
|
||||
#include "call/call-p.h"
|
||||
#include "chat/chat-message/chat-message-p.h"
|
||||
#include "chat/chat-room/chat-room-p.h"
|
||||
#include "chat/chat-room/client-group-to-basic-chat-room.h"
|
||||
|
|
@ -63,28 +63,69 @@ void ChatMessagePrivate::setIsReadOnly (bool readOnly) {
|
|||
isReadOnly = readOnly;
|
||||
}
|
||||
|
||||
void ChatMessagePrivate::setState (ChatMessage::State s, bool force) {
|
||||
void ChatMessagePrivate::setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState) {
|
||||
L_Q();
|
||||
|
||||
if (!(q->getChatRoom()->getCapabilities() & AbstractChatRoom::Capabilities::Conference)
|
||||
|| (linphone_config_get_bool(linphone_core_get_config(q->getChatRoom()->getCore()->getCCore()),
|
||||
"misc", "enable_simple_group_chat_message_state", TRUE
|
||||
))
|
||||
) {
|
||||
setState(newState);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dbKey.isValid())
|
||||
return;
|
||||
|
||||
unique_ptr<MainDb> &mainDb = q->getChatRoom()->getCore()->getPrivate()->mainDb;
|
||||
shared_ptr<EventLog> eventLog = mainDb->getEventFromKey(dbKey);
|
||||
ChatMessage::State currentState = mainDb->getChatMessageParticipantState(eventLog, participantAddress);
|
||||
if (!validStateTransition(currentState, newState))
|
||||
return;
|
||||
|
||||
mainDb->setChatMessageParticipantState(eventLog, participantAddress, newState);
|
||||
|
||||
list<ChatMessage::State> states = mainDb->getChatMessageParticipantStates(eventLog);
|
||||
size_t nbDisplayedStates = 0;
|
||||
size_t nbDeliveredToUserStates = 0;
|
||||
size_t nbNotDeliveredStates = 0;
|
||||
for (const auto &state : states) {
|
||||
switch (state) {
|
||||
case ChatMessage::State::Displayed:
|
||||
nbDisplayedStates++;
|
||||
break;
|
||||
case ChatMessage::State::DeliveredToUser:
|
||||
nbDeliveredToUserStates++;
|
||||
break;
|
||||
case ChatMessage::State::NotDelivered:
|
||||
nbNotDeliveredStates++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nbNotDeliveredStates > 0)
|
||||
setState(ChatMessage::State::NotDelivered);
|
||||
else if (nbDisplayedStates == states.size())
|
||||
setState(ChatMessage::State::Displayed);
|
||||
else if ((nbDisplayedStates + nbDeliveredToUserStates) == states.size())
|
||||
setState(ChatMessage::State::DeliveredToUser);
|
||||
}
|
||||
|
||||
void ChatMessagePrivate::setState (ChatMessage::State newState, bool force) {
|
||||
L_Q();
|
||||
|
||||
if (force)
|
||||
state = s;
|
||||
state = newState;
|
||||
|
||||
if (s == state)
|
||||
return;
|
||||
|
||||
if (
|
||||
(state == ChatMessage::State::Displayed || state == ChatMessage::State::DeliveredToUser) &&
|
||||
(
|
||||
s == ChatMessage::State::DeliveredToUser ||
|
||||
s == ChatMessage::State::Delivered ||
|
||||
s == ChatMessage::State::NotDelivered
|
||||
)
|
||||
)
|
||||
if (!validStateTransition(state, newState))
|
||||
return;
|
||||
|
||||
lInfo() << "Chat message " << this << ": moving from " << Utils::toString(state) <<
|
||||
" to " << Utils::toString(s);
|
||||
state = s;
|
||||
" to " << Utils::toString(newState);
|
||||
state = newState;
|
||||
|
||||
LinphoneChatMessage *msg = L_GET_C_BACK_PTR(q);
|
||||
if (linphone_chat_message_get_message_state_changed_cb(msg))
|
||||
|
|
@ -401,18 +442,23 @@ void ChatMessagePrivate::notifyReceiving () {
|
|||
|
||||
LinphoneChatRoom *chatRoom = L_GET_C_BACK_PTR(q->getChatRoom());
|
||||
LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(chatRoom);
|
||||
LinphoneChatRoomCbsParticipantAddedCb cb = linphone_chat_room_cbs_get_chat_message_received(cbs);
|
||||
shared_ptr<ConferenceChatMessageEvent> event = make_shared<ConferenceChatMessageEvent>(
|
||||
::time(nullptr), q->getSharedFromThis()
|
||||
);
|
||||
if (cb)
|
||||
cb(chatRoom, L_GET_C_BACK_PTR(event));
|
||||
// Legacy
|
||||
q->getChatRoom()->getPrivate()->notifyChatMessageReceived(q->getSharedFromThis());
|
||||
|
||||
LinphoneChatRoomCbsShouldChatMessageBeStoredCb shouldMessageBeStoredCb = linphone_chat_room_cbs_get_chat_message_should_be_stored(cbs);
|
||||
if (shouldMessageBeStoredCb)
|
||||
shouldMessageBeStoredCb(chatRoom, L_GET_C_BACK_PTR(q->getSharedFromThis()));
|
||||
|
||||
if (toBeStored)
|
||||
storeInDb();
|
||||
|
||||
shared_ptr<ConferenceChatMessageEvent> event = make_shared<ConferenceChatMessageEvent>(
|
||||
::time(nullptr), q->getSharedFromThis()
|
||||
);
|
||||
LinphoneChatRoomCbsChatMessageReceivedCb messageReceivedCb = linphone_chat_room_cbs_get_chat_message_received(cbs);
|
||||
if (messageReceivedCb)
|
||||
messageReceivedCb(chatRoom, L_GET_C_BACK_PTR(event));
|
||||
// Legacy
|
||||
q->getChatRoom()->getPrivate()->notifyChatMessageReceived(q->getSharedFromThis());
|
||||
|
||||
q->sendDeliveryNotification(LinphoneReasonNone);
|
||||
}
|
||||
|
||||
|
|
@ -665,7 +711,7 @@ void ChatMessagePrivate::send () {
|
|||
} else {
|
||||
msgOp->send_message(ContentType::PlainText.asString().c_str(), internalContent.getBodyAsUtf8String().c_str());
|
||||
}
|
||||
|
||||
|
||||
// Restore FileContents and remove FileTransferContents
|
||||
list<Content*>::iterator it = contents.begin();
|
||||
while (it != contents.end()) {
|
||||
|
|
@ -712,7 +758,7 @@ void ChatMessagePrivate::storeInDb () {
|
|||
updateInDb();
|
||||
} else {
|
||||
shared_ptr<EventLog> eventLog = make_shared<ConferenceChatMessageEvent>(time, q->getSharedFromThis());
|
||||
q->getChatRoom()->getCore()->getPrivate()->mainDb->addEvent(eventLog);
|
||||
q->getChatRoom()->getPrivate()->addEvent(eventLog);
|
||||
|
||||
if (direction == ChatMessage::Direction::Incoming) {
|
||||
if (hasFileTransferContent()) {
|
||||
|
|
@ -751,6 +797,24 @@ void ChatMessagePrivate::updateInDb () {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool ChatMessagePrivate::validStateTransition (ChatMessage::State currentState, ChatMessage::State newState) {
|
||||
if (newState == currentState)
|
||||
return false;
|
||||
|
||||
if (
|
||||
(currentState == ChatMessage::State::Displayed || currentState == ChatMessage::State::DeliveredToUser) &&
|
||||
(
|
||||
newState == ChatMessage::State::DeliveredToUser ||
|
||||
newState == ChatMessage::State::Delivered ||
|
||||
newState == ChatMessage::State::NotDelivered
|
||||
)
|
||||
)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
ChatMessage::ChatMessage (const shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction) :
|
||||
Object(*new ChatMessagePrivate), CoreAccessor(chatRoom->getCore()) {
|
||||
L_D();
|
||||
|
|
@ -926,12 +990,6 @@ void ChatMessage::removeCustomHeader (const string &headerName) {
|
|||
d->customHeaders.erase(headerName);
|
||||
}
|
||||
|
||||
void ChatMessage::updateState (State state) {
|
||||
L_D();
|
||||
|
||||
d->setState(state);
|
||||
}
|
||||
|
||||
void ChatMessage::send () {
|
||||
L_D();
|
||||
|
||||
|
|
@ -981,48 +1039,50 @@ void ChatMessage::cancelFileTransfer () {
|
|||
int ChatMessage::putCharacter (uint32_t character) {
|
||||
L_D();
|
||||
|
||||
shared_ptr<Core> core = getCore();
|
||||
if (linphone_core_realtime_text_enabled(core->getCCore())) {
|
||||
static const uint32_t new_line = 0x2028;
|
||||
static const uint32_t crlf = 0x0D0A;
|
||||
static const uint32_t lf = 0x0A;
|
||||
static const uint32_t new_line = 0x2028;
|
||||
static const uint32_t crlf = 0x0D0A;
|
||||
static const uint32_t lf = 0x0A;
|
||||
|
||||
shared_ptr<AbstractChatRoom> chatRoom = getChatRoom();
|
||||
shared_ptr<AbstractChatRoom> chatRoom = getChatRoom();
|
||||
if (!(chatRoom->getCapabilities() & LinphonePrivate::ChatRoom::Capabilities::RealTimeText))
|
||||
return -1;
|
||||
|
||||
shared_ptr<LinphonePrivate::RealTimeTextChatRoom> rttcr =
|
||||
static_pointer_cast<LinphonePrivate::RealTimeTextChatRoom>(chatRoom);
|
||||
LinphoneCall *call = rttcr->getCall();
|
||||
shared_ptr<LinphonePrivate::RealTimeTextChatRoom> rttcr =
|
||||
static_pointer_cast<LinphonePrivate::RealTimeTextChatRoom>(chatRoom);
|
||||
if (!rttcr)
|
||||
return -1;
|
||||
|
||||
if (!call || !linphone_call_get_stream(call, LinphoneStreamTypeText))
|
||||
return -1;
|
||||
shared_ptr<Call> call = rttcr->getCall();
|
||||
if (!call || !call->getPrivate()->getMediaStream(LinphoneStreamTypeText))
|
||||
return -1;
|
||||
|
||||
if (character == new_line || character == crlf || character == lf) {
|
||||
if (lp_config_get_int(core->getCCore()->config, "misc", "store_rtt_messages", 1) == 1) {
|
||||
// TODO: History.
|
||||
lDebug() << "New line sent, forge a message with content " << d->rttMessage.c_str();
|
||||
d->setTime(ms_time(0));
|
||||
d->state = State::Displayed;
|
||||
// d->direction = Direction::Outgoing;
|
||||
// setFromAddress(Address(
|
||||
// linphone_address_as_string(linphone_address_new(linphone_core_get_identity(core->getCCore())))
|
||||
// ));
|
||||
// linphone_chat_message_store(L_GET_C_BACK_PTR(this));
|
||||
d->rttMessage = "";
|
||||
}
|
||||
} else {
|
||||
char *value = LinphonePrivate::Utils::utf8ToChar(character);
|
||||
d->rttMessage = d->rttMessage + string(value);
|
||||
lDebug() << "Sent RTT character: " << value << "(" << (unsigned long)character <<
|
||||
"), pending text is " << d->rttMessage.c_str();
|
||||
delete value;
|
||||
if (character == new_line || character == crlf || character == lf) {
|
||||
shared_ptr<Core> core = getCore();
|
||||
if (lp_config_get_int(core->getCCore()->config, "misc", "store_rtt_messages", 1) == 1) {
|
||||
// TODO: History.
|
||||
lDebug() << "New line sent, forge a message with content " << d->rttMessage.c_str();
|
||||
d->setTime(ms_time(0));
|
||||
d->state = State::Displayed;
|
||||
// d->direction = Direction::Outgoing;
|
||||
// setFromAddress(Address(
|
||||
// linphone_address_as_string(linphone_address_new(linphone_core_get_identity(core->getCCore())))
|
||||
// ));
|
||||
// linphone_chat_message_store(L_GET_C_BACK_PTR(this));
|
||||
d->rttMessage = "";
|
||||
}
|
||||
|
||||
text_stream_putchar32(reinterpret_cast<TextStream *>(
|
||||
linphone_call_get_stream(call, LinphoneStreamTypeText)), character
|
||||
);
|
||||
return 0;
|
||||
} else {
|
||||
char *value = LinphonePrivate::Utils::utf8ToChar(character);
|
||||
d->rttMessage = d->rttMessage + string(value);
|
||||
lDebug() << "Sent RTT character: " << value << "(" << (unsigned long)character <<
|
||||
"), pending text is " << d->rttMessage.c_str();
|
||||
delete[] value;
|
||||
}
|
||||
return -1;
|
||||
|
||||
text_stream_putchar32(
|
||||
reinterpret_cast<TextStream *>(call->getPrivate()->getMediaStream(LinphoneStreamTypeText)),
|
||||
character
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor {
|
|||
friend class ChatRoomPrivate;
|
||||
friend class CpimChatMessageModifier;
|
||||
friend class FileTransferChatMessageModifier;
|
||||
friend class Imdn;
|
||||
friend class MainDb;
|
||||
friend class MainDbPrivate;
|
||||
friend class RealTimeTextChatRoomPrivate;
|
||||
|
|
@ -63,7 +64,6 @@ public:
|
|||
// ----- TODO: Remove me.
|
||||
void cancelFileTransfer ();
|
||||
int putCharacter (uint32_t character);
|
||||
void updateState (State state);
|
||||
void sendDeliveryNotification (LinphoneReason reason);
|
||||
void sendDisplayNotification ();
|
||||
void setIsSecured (bool isSecured);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ public:
|
|||
|
||||
virtual void sendChatMessage (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
|
||||
|
||||
virtual void addEvent (const std::shared_ptr<EventLog> &eventLog) = 0;
|
||||
|
||||
virtual void addTransientEvent (const std::shared_ptr<EventLog> &eventLog) = 0;
|
||||
virtual void removeTransientEvent (const std::shared_ptr<EventLog> &eventLog) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ public:
|
|||
virtual State getState () const = 0;
|
||||
virtual bool hasBeenLeft () const = 0;
|
||||
|
||||
virtual std::list<std::shared_ptr<EventLog>> getMessageHistory (int nLast) const = 0;
|
||||
virtual std::list<std::shared_ptr<EventLog>> getMessageHistoryRange (int begin, int end) const = 0;
|
||||
virtual std::list<std::shared_ptr<EventLog>> getHistory (int nLast) const = 0;
|
||||
virtual std::list<std::shared_ptr<EventLog>> getHistoryRange (int begin, int end) const = 0;
|
||||
virtual int getHistorySize () const = 0;
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public:
|
|||
}
|
||||
|
||||
void onCallSessionStateChanged (
|
||||
const shared_ptr<const CallSession> &session,
|
||||
const shared_ptr<CallSession> &session,
|
||||
CallSession::State newState,
|
||||
const string &message
|
||||
) override {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ bool ChatRoomId::operator!= (const ChatRoomId &chatRoomId) const {
|
|||
bool ChatRoomId::operator< (const ChatRoomId &chatRoomId) const {
|
||||
L_D();
|
||||
const ChatRoomIdPrivate *dChatRoomId = chatRoomId.getPrivate();
|
||||
return d->peerAddress < dChatRoomId->peerAddress || d->localAddress < dChatRoomId->localAddress;
|
||||
return d->peerAddress < dChatRoomId->peerAddress
|
||||
|| (d->peerAddress == dChatRoomId->peerAddress && d->localAddress < dChatRoomId->localAddress);
|
||||
}
|
||||
|
||||
const IdentityAddress &ChatRoomId::getPeerAddress () const {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ public:
|
|||
void sendChatMessage (const std::shared_ptr<ChatMessage> &chatMessage) override;
|
||||
void sendIsComposingNotification ();
|
||||
|
||||
void addEvent (const std::shared_ptr<EventLog> &eventLog) override;
|
||||
|
||||
void addTransientEvent (const std::shared_ptr<EventLog> &eventLog) override;
|
||||
void removeTransientEvent (const std::shared_ptr<EventLog> &eventLog) override;
|
||||
|
||||
|
|
@ -59,7 +61,7 @@ public:
|
|||
|
||||
LinphoneReason onSipMessageReceived (SalOp *op, const SalMessage *message) override;
|
||||
void onChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override;
|
||||
void onImdnReceived (const std::string &text);
|
||||
void onImdnReceived (const std::shared_ptr<ChatMessage> &chatMessage);
|
||||
void onIsComposingReceived (const Address &remoteAddress, const std::string &text);
|
||||
void onIsComposingRefreshNeeded () override;
|
||||
void onIsComposingStateChanged (bool isComposing) override;
|
||||
|
|
@ -76,7 +78,6 @@ private:
|
|||
time_t creationTime = std::time(nullptr);
|
||||
time_t lastUpdateTime = std::time(nullptr);
|
||||
|
||||
std::shared_ptr<ChatMessage> pendingMessage;
|
||||
std::unique_ptr<IsComposing> isComposingHandler;
|
||||
|
||||
bool isComposing = false;
|
||||
|
|
|
|||
|
|
@ -90,6 +90,13 @@ void ChatRoomPrivate::sendIsComposingNotification () {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ChatRoomPrivate::addEvent (const shared_ptr<EventLog> &eventLog) {
|
||||
L_Q();
|
||||
|
||||
q->getCore()->getPrivate()->mainDb->addEvent(eventLog);
|
||||
setLastUpdateTime(eventLog->getCreationTime());
|
||||
}
|
||||
|
||||
void ChatRoomPrivate::addTransientEvent (const shared_ptr<EventLog> &eventLog) {
|
||||
auto it = find(transientEvents.begin(), transientEvents.end(), eventLog);
|
||||
if (it == transientEvents.end())
|
||||
|
|
@ -182,7 +189,6 @@ void ChatRoomPrivate::notifyUndecryptableChatMessageReceived (const shared_ptr<C
|
|||
LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessage *message) {
|
||||
L_Q();
|
||||
|
||||
bool increaseMsgCount = true;
|
||||
LinphoneReason reason = LinphoneReasonNone;
|
||||
shared_ptr<ChatMessage> msg;
|
||||
|
||||
|
|
@ -217,29 +223,18 @@ LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessag
|
|||
|
||||
if (msg->getPrivate()->getContentType() == ContentType::ImIsComposing) {
|
||||
onIsComposingReceived(msg->getFromAddress(), msg->getPrivate()->getText());
|
||||
increaseMsgCount = FALSE;
|
||||
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) {
|
||||
goto end;
|
||||
}
|
||||
} else if (msg->getPrivate()->getContentType() == ContentType::Imdn) {
|
||||
onImdnReceived(msg->getPrivate()->getText());
|
||||
increaseMsgCount = FALSE;
|
||||
onImdnReceived(msg);
|
||||
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (increaseMsgCount) {
|
||||
/* Mark the message as pending so that if ChatRoom::markAsRead() is called in the
|
||||
* ChatRoomPrivate::chatMessageReceived() callback, it will effectively be marked as
|
||||
* being read before being stored. */
|
||||
pendingMessage = msg;
|
||||
}
|
||||
|
||||
onChatMessageReceived(msg);
|
||||
|
||||
pendingMessage = nullptr;
|
||||
|
||||
end:
|
||||
return reason;
|
||||
}
|
||||
|
|
@ -251,9 +246,8 @@ void ChatRoomPrivate::onChatMessageReceived (const shared_ptr<ChatMessage> &chat
|
|||
chatMessage->getPrivate()->notifyReceiving();
|
||||
}
|
||||
|
||||
void ChatRoomPrivate::onImdnReceived (const string &text) {
|
||||
L_Q();
|
||||
Imdn::parse(*q, text);
|
||||
void ChatRoomPrivate::onImdnReceived (const shared_ptr<ChatMessage> &chatMessage) {
|
||||
Imdn::parse(chatMessage);
|
||||
}
|
||||
|
||||
void ChatRoomPrivate::onIsComposingReceived (const Address &remoteAddress, const string &text) {
|
||||
|
|
@ -321,12 +315,20 @@ ChatRoom::State ChatRoom::getState () const {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
list<shared_ptr<EventLog>> ChatRoom::getMessageHistory (int nLast) const {
|
||||
return getCore()->getPrivate()->mainDb->getHistory(getChatRoomId(), nLast, MainDb::Filter::ConferenceChatMessageFilter);
|
||||
}
|
||||
|
||||
list<shared_ptr<EventLog>> ChatRoom::getMessageHistoryRange (int begin, int end) const {
|
||||
return getCore()->getPrivate()->mainDb->getHistoryRange(getChatRoomId(), begin, end, MainDb::Filter::ConferenceChatMessageFilter);
|
||||
}
|
||||
|
||||
list<shared_ptr<EventLog>> ChatRoom::getHistory (int nLast) const {
|
||||
return getCore()->getPrivate()->mainDb->getHistory(getChatRoomId(), nLast);
|
||||
return getCore()->getPrivate()->mainDb->getHistory(getChatRoomId(), nLast, MainDb::Filter::ConferenceInfoNoDeviceFilter);
|
||||
}
|
||||
|
||||
list<shared_ptr<EventLog>> ChatRoom::getHistoryRange (int begin, int end) const {
|
||||
return getCore()->getPrivate()->mainDb->getHistoryRange(getChatRoomId(), begin, end);
|
||||
return getCore()->getPrivate()->mainDb->getHistoryRange(getChatRoomId(), begin, end, MainDb::Filter::ConferenceInfoNoDeviceFilter);
|
||||
}
|
||||
|
||||
int ChatRoom::getHistorySize () const {
|
||||
|
|
@ -423,11 +425,6 @@ void ChatRoom::markAsRead () {
|
|||
chatMessage->sendDisplayNotification();
|
||||
|
||||
dCore->mainDb->markChatMessagesAsRead(d->chatRoomId);
|
||||
|
||||
if (d->pendingMessage) {
|
||||
d->pendingMessage->updateState(ChatMessage::State::Displayed);
|
||||
d->pendingMessage->sendDisplayNotification();
|
||||
}
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ public:
|
|||
|
||||
State getState () const override;
|
||||
|
||||
std::list<std::shared_ptr<EventLog>> getMessageHistory (int nLast) const override;
|
||||
std::list<std::shared_ptr<EventLog>> getMessageHistoryRange (int begin, int end) const override;
|
||||
std::list<std::shared_ptr<EventLog>> getHistory (int nLast) const override;
|
||||
std::list<std::shared_ptr<EventLog>> getHistoryRange (int begin, int end) const override;
|
||||
int getHistorySize () const override;
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ public:
|
|||
void onChatRoomDeleteRequested (const std::shared_ptr<AbstractChatRoom> &chatRoom) override;
|
||||
|
||||
// CallSessionListener
|
||||
void onCallSessionSetReleased (const std::shared_ptr<const CallSession> &session) override;
|
||||
void onCallSessionStateChanged (const std::shared_ptr<const CallSession> &session, CallSession::State state, const std::string &message) override;
|
||||
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;
|
||||
|
||||
private:
|
||||
CallSessionListener *callSessionListener = this;
|
||||
|
|
|
|||
|
|
@ -20,16 +20,14 @@
|
|||
#include "linphone/utils/utils.h"
|
||||
|
||||
#include "address/address-p.h"
|
||||
#include "c-wrapper/c-wrapper.h"
|
||||
#include "basic-chat-room.h"
|
||||
#include "basic-to-client-group-chat-room.h"
|
||||
#include "c-wrapper/c-wrapper.h"
|
||||
#include "client-group-chat-room-p.h"
|
||||
#include "conference/handlers/remote-conference-event-handler.h"
|
||||
#include "conference/participant-p.h"
|
||||
#include "conference/remote-conference-p.h"
|
||||
#include "conference/session/call-session-p.h"
|
||||
#include "core/core-p.h"
|
||||
#include "event-log/events.h"
|
||||
#include "logger/logger.h"
|
||||
#include "sal/refer-op.h"
|
||||
|
||||
|
|
@ -65,12 +63,11 @@ shared_ptr<CallSession> ClientGroupChatRoomPrivate::createSession () {
|
|||
if (capabilities & ClientGroupChatRoom::Capabilities::OneToOne)
|
||||
csp.addCustomHeader("One-To-One-Chat-Room", "true");
|
||||
|
||||
shared_ptr<Participant> focus = qConference->getPrivate()->focus;
|
||||
shared_ptr<CallSession> session = focus->getPrivate()->createSession(*q, &csp, false, callSessionListener);
|
||||
const Address &myAddress = q->getMe()->getAddress();
|
||||
Address myCleanedAddress(myAddress);
|
||||
myCleanedAddress.removeUriParam("gr"); // Remove gr parameter for INVITE
|
||||
session->configure(LinphoneCallOutgoing, nullptr, nullptr, myCleanedAddress, focus->getPrivate()->getDevices().front()->getAddress());
|
||||
ParticipantPrivate *dFocus = qConference->getPrivate()->focus->getPrivate();
|
||||
shared_ptr<CallSession> session = dFocus->createSession(*q, &csp, false, callSessionListener);
|
||||
Address myCleanedAddress(q->getMe()->getAddress());
|
||||
myCleanedAddress.removeUriParam("gr"); // Remove gr parameter for INVITE.
|
||||
session->configure(LinphoneCallOutgoing, nullptr, nullptr, myCleanedAddress, dFocus->getDevices().front()->getAddress());
|
||||
session->initiateOutgoing();
|
||||
session->getPrivate()->createOp();
|
||||
return session;
|
||||
|
|
@ -122,7 +119,7 @@ void ClientGroupChatRoomPrivate::onChatRoomDeleteRequested (const shared_ptr<Abs
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ClientGroupChatRoomPrivate::onCallSessionSetReleased (const shared_ptr<const CallSession> &session) {
|
||||
void ClientGroupChatRoomPrivate::onCallSessionSetReleased (const shared_ptr<CallSession> &session) {
|
||||
L_Q_T(RemoteConference, qConference);
|
||||
|
||||
ParticipantPrivate *participantPrivate = qConference->getPrivate()->focus->getPrivate();
|
||||
|
|
@ -131,7 +128,7 @@ void ClientGroupChatRoomPrivate::onCallSessionSetReleased (const shared_ptr<cons
|
|||
}
|
||||
|
||||
void ClientGroupChatRoomPrivate::onCallSessionStateChanged (
|
||||
const shared_ptr<const CallSession> &session,
|
||||
const shared_ptr<CallSession> &session,
|
||||
CallSession::State newState,
|
||||
const string &message
|
||||
) {
|
||||
|
|
@ -152,9 +149,14 @@ void ClientGroupChatRoomPrivate::onCallSessionStateChanged (
|
|||
if (q->getState() == ChatRoom::State::CreationPending)
|
||||
setState(ChatRoom::State::CreationFailed);
|
||||
else if (q->getState() == ChatRoom::State::TerminationPending) {
|
||||
// Go to state TerminationFailed and then back to Created since it has not been terminated
|
||||
setState(ChatRoom::State::TerminationFailed);
|
||||
setState(ChatRoom::State::Created);
|
||||
if (session->getReason() == LinphoneReasonNotFound) {
|
||||
// Somehow the chat room is no longer know on the server, so terminate it
|
||||
q->onConferenceTerminated(q->getConferenceAddress());
|
||||
} else {
|
||||
// Go to state TerminationFailed and then back to Created since it has not been terminated
|
||||
setState(ChatRoom::State::TerminationFailed);
|
||||
setState(ChatRoom::State::Created);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -206,6 +208,11 @@ RemoteConference(core, me->getAddress(), nullptr) {
|
|||
dConference->eventHandler->subscribe(getChatRoomId());
|
||||
}
|
||||
|
||||
ClientGroupChatRoom::~ClientGroupChatRoom () {
|
||||
L_D();
|
||||
d->setCallSessionListener(nullptr);
|
||||
}
|
||||
|
||||
shared_ptr<Core> ClientGroupChatRoom::getCore () const {
|
||||
return ChatRoom::getCore();
|
||||
}
|
||||
|
|
@ -396,7 +403,10 @@ void ClientGroupChatRoom::join () {
|
|||
if (!session && ((getState() == ChatRoom::State::Instantiated) || (getState() == ChatRoom::State::Terminated))) {
|
||||
d->bgTask.start();
|
||||
session = d->createSession();
|
||||
session->startInvite(nullptr, "", nullptr);
|
||||
}
|
||||
if (session) {
|
||||
if (getState() != ChatRoom::State::TerminationPending)
|
||||
session->startInvite(nullptr, "", nullptr);
|
||||
d->setState(ChatRoom::State::CreationPending);
|
||||
}
|
||||
}
|
||||
|
|
@ -442,7 +452,7 @@ void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) {
|
|||
L_D_T(RemoteConference, dConference);
|
||||
dConference->eventHandler->resetLastNotify();
|
||||
d->setState(ChatRoom::State::Terminated);
|
||||
getCore()->getPrivate()->mainDb->addEvent(make_shared<ConferenceEvent>(
|
||||
d->addEvent(make_shared<ConferenceEvent>(
|
||||
EventLog::Type::ConferenceTerminated,
|
||||
time(nullptr),
|
||||
d->chatRoomId
|
||||
|
|
@ -471,7 +481,7 @@ void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) {
|
|||
// TODO: Bug. Event is inserted many times.
|
||||
// Avoid this in the future. Deal with signals/slots system.
|
||||
#if 0
|
||||
getCore()->getPrivate()->mainDb->addEvent(make_shared<ConferenceEvent>(
|
||||
d->addEvent(make_shared<ConferenceEvent>(
|
||||
EventLog::Type::ConferenceCreated,
|
||||
time(nullptr),
|
||||
d->chatRoomId
|
||||
|
|
@ -481,6 +491,7 @@ void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) {
|
|||
}
|
||||
|
||||
void ClientGroupChatRoom::onParticipantAdded (const shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) {
|
||||
L_D();
|
||||
L_D_T(RemoteConference, dConference);
|
||||
|
||||
const IdentityAddress &addr = event->getParticipantAddress();
|
||||
|
|
@ -499,7 +510,7 @@ void ClientGroupChatRoom::onParticipantAdded (const shared_ptr<ConferencePartici
|
|||
if (isFullState)
|
||||
return;
|
||||
|
||||
getCore()->getPrivate()->mainDb->addEvent(event);
|
||||
d->addEvent(event);
|
||||
|
||||
LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this);
|
||||
LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr);
|
||||
|
|
@ -511,6 +522,7 @@ void ClientGroupChatRoom::onParticipantAdded (const shared_ptr<ConferencePartici
|
|||
void ClientGroupChatRoom::onParticipantRemoved (const shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) {
|
||||
(void)isFullState;
|
||||
|
||||
L_D();
|
||||
L_D_T(RemoteConference, dConference);
|
||||
|
||||
const IdentityAddress &addr = event->getParticipantAddress();
|
||||
|
|
@ -521,7 +533,7 @@ void ClientGroupChatRoom::onParticipantRemoved (const shared_ptr<ConferenceParti
|
|||
}
|
||||
|
||||
dConference->participants.remove(participant);
|
||||
getCore()->getPrivate()->mainDb->addEvent(event);
|
||||
d->addEvent(event);
|
||||
|
||||
LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this);
|
||||
LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr);
|
||||
|
|
@ -531,6 +543,8 @@ void ClientGroupChatRoom::onParticipantRemoved (const shared_ptr<ConferenceParti
|
|||
}
|
||||
|
||||
void ClientGroupChatRoom::onParticipantSetAdmin (const shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) {
|
||||
L_D();
|
||||
|
||||
const IdentityAddress &addr = event->getParticipantAddress();
|
||||
shared_ptr<Participant> participant;
|
||||
if (isMe(addr))
|
||||
|
|
@ -550,7 +564,7 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const shared_ptr<ConferencePart
|
|||
if (isFullState)
|
||||
return;
|
||||
|
||||
getCore()->getPrivate()->mainDb->addEvent(event);
|
||||
d->addEvent(event);
|
||||
|
||||
LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this);
|
||||
LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr);
|
||||
|
|
@ -560,6 +574,8 @@ void ClientGroupChatRoom::onParticipantSetAdmin (const shared_ptr<ConferencePart
|
|||
}
|
||||
|
||||
void ClientGroupChatRoom::onSubjectChanged (const shared_ptr<ConferenceSubjectEvent> &event, bool isFullState) {
|
||||
L_D();
|
||||
|
||||
if (getSubject() == event->getSubject())
|
||||
return; // No change in the local subject, do not notify
|
||||
RemoteConference::setSubject(event->getSubject());
|
||||
|
|
@ -567,7 +583,7 @@ void ClientGroupChatRoom::onSubjectChanged (const shared_ptr<ConferenceSubjectEv
|
|||
if (isFullState)
|
||||
return;
|
||||
|
||||
getCore()->getPrivate()->mainDb->addEvent(event);
|
||||
d->addEvent(event);
|
||||
|
||||
LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this);
|
||||
LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr);
|
||||
|
|
@ -577,6 +593,8 @@ void ClientGroupChatRoom::onSubjectChanged (const shared_ptr<ConferenceSubjectEv
|
|||
}
|
||||
|
||||
void ClientGroupChatRoom::onParticipantDeviceAdded (const shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) {
|
||||
L_D();
|
||||
|
||||
const IdentityAddress &addr = event->getParticipantAddress();
|
||||
shared_ptr<Participant> participant;
|
||||
if (isMe(addr))
|
||||
|
|
@ -592,7 +610,7 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const shared_ptr<ConferenceP
|
|||
if (isFullState)
|
||||
return;
|
||||
|
||||
getCore()->getPrivate()->mainDb->addEvent(event);
|
||||
d->addEvent(event);
|
||||
|
||||
LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this);
|
||||
LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr);
|
||||
|
|
@ -602,6 +620,8 @@ void ClientGroupChatRoom::onParticipantDeviceAdded (const shared_ptr<ConferenceP
|
|||
}
|
||||
|
||||
void ClientGroupChatRoom::onParticipantDeviceRemoved (const shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) {
|
||||
L_D();
|
||||
|
||||
(void)isFullState;
|
||||
|
||||
const IdentityAddress &addr = event->getParticipantAddress();
|
||||
|
|
@ -615,7 +635,7 @@ void ClientGroupChatRoom::onParticipantDeviceRemoved (const shared_ptr<Conferenc
|
|||
return;
|
||||
}
|
||||
participant->getPrivate()->removeDevice(event->getDeviceAddress());
|
||||
getCore()->getPrivate()->mainDb->addEvent(event);
|
||||
d->addEvent(event);
|
||||
|
||||
LinphoneChatRoom *cr = L_GET_C_BACK_PTR(this);
|
||||
LinphoneChatRoomCbs *cbs = linphone_chat_room_get_callbacks(cr);
|
||||
|
|
|
|||
|
|
@ -55,8 +55,10 @@ public:
|
|||
unsigned int lastNotifyId
|
||||
);
|
||||
|
||||
~ClientGroupChatRoom ();
|
||||
|
||||
std::shared_ptr<Core> getCore () const;
|
||||
|
||||
|
||||
void allowCpim (bool value) override;
|
||||
void allowMultipart (bool value) override;
|
||||
bool canHandleCpim () const override;
|
||||
|
|
@ -100,11 +102,11 @@ private:
|
|||
void onConferenceTerminated (const IdentityAddress &addr) override;
|
||||
void onFirstNotifyReceived (const IdentityAddress &addr) override;
|
||||
void onParticipantAdded (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) override;
|
||||
void onParticipantDeviceAdded (const std::shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) override;
|
||||
void onParticipantDeviceRemoved (const std::shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) override;
|
||||
void onParticipantRemoved (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) override;
|
||||
void onParticipantSetAdmin (const std::shared_ptr<ConferenceParticipantEvent> &event, bool isFullState) override;
|
||||
void onSubjectChanged (const std::shared_ptr<ConferenceSubjectEvent> &event, bool isFullState) override;
|
||||
void onParticipantDeviceAdded (const std::shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) override;
|
||||
void onParticipantDeviceRemoved (const std::shared_ptr<ConferenceParticipantDeviceEvent> &event, bool isFullState) override;
|
||||
|
||||
L_DECLARE_PRIVATE(ClientGroupChatRoom);
|
||||
L_DISABLE_COPY(ClientGroupChatRoom);
|
||||
|
|
|
|||
|
|
@ -52,14 +52,14 @@ public:
|
|||
setState(AbstractChatRoom::State::Deleted);
|
||||
}
|
||||
|
||||
void onCallSessionSetReleased (const std::shared_ptr<const CallSession> &session) override {
|
||||
void onCallSessionSetReleased (const shared_ptr<CallSession> &session) override {
|
||||
if (!(chatRoom->getCapabilities() & ChatRoom::Capabilities::Conference))
|
||||
return;
|
||||
static_pointer_cast<ClientGroupChatRoom>(chatRoom)->getPrivate()->onCallSessionSetReleased(session);
|
||||
}
|
||||
|
||||
void onCallSessionStateChanged (
|
||||
const shared_ptr<const CallSession> &session,
|
||||
const shared_ptr<CallSession> &session,
|
||||
CallSession::State newState,
|
||||
const string &message
|
||||
) override {
|
||||
|
|
@ -111,7 +111,7 @@ void ClientGroupToBasicChatRoom::addParticipant (
|
|||
ProxyChatRoom::addParticipant(participantAddress, params, hasMedia);
|
||||
}
|
||||
void ClientGroupToBasicChatRoom::addParticipants (
|
||||
const std::list<IdentityAddress> &addresses,
|
||||
const list<IdentityAddress> &addresses,
|
||||
const CallSessionParams *params,
|
||||
bool hasMedia
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#define _L_PROXY_CHAT_ROOM_P_H_
|
||||
|
||||
#include "abstract-chat-room-p.h"
|
||||
#include "proxy-chat-room.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
|
@ -44,6 +45,10 @@ public:
|
|||
chatRoom->getPrivate()->sendChatMessage(chatMessage);
|
||||
}
|
||||
|
||||
inline void addEvent (const std::shared_ptr<EventLog> &eventLog) override {
|
||||
chatRoom->getPrivate()->addEvent(eventLog);
|
||||
}
|
||||
|
||||
inline void addTransientEvent (const std::shared_ptr<EventLog> &eventLog) override {
|
||||
chatRoom->getPrivate()->addTransientEvent(eventLog);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,6 +195,16 @@ bool ProxyChatRoom::hasBeenLeft () const {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
list<shared_ptr<EventLog>> ProxyChatRoom::getMessageHistory (int nLast) const {
|
||||
L_D();
|
||||
return d->chatRoom->getMessageHistory(nLast);
|
||||
}
|
||||
|
||||
list<shared_ptr<EventLog>> ProxyChatRoom::getMessageHistoryRange (int begin, int end) const {
|
||||
L_D();
|
||||
return d->chatRoom->getMessageHistoryRange(begin, end);
|
||||
}
|
||||
|
||||
list<shared_ptr<EventLog>> ProxyChatRoom::getHistory (int nLast) const {
|
||||
L_D();
|
||||
return d->chatRoom->getHistory(nLast);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ public:
|
|||
State getState () const override;
|
||||
bool hasBeenLeft () const override;
|
||||
|
||||
std::list<std::shared_ptr<EventLog>> getMessageHistory (int nLast) const override;
|
||||
std::list<std::shared_ptr<EventLog>> getMessageHistoryRange (int begin, int end) const override;
|
||||
std::list<std::shared_ptr<EventLog>> getHistory (int nLast) const override;
|
||||
std::list<std::shared_ptr<EventLog>> getHistoryRange (int begin, int end) const override;
|
||||
int getHistorySize () const override;
|
||||
|
|
|
|||
|
|
@ -29,13 +29,19 @@ LINPHONE_BEGIN_NAMESPACE
|
|||
|
||||
class RealTimeTextChatRoomPrivate : public BasicChatRoomPrivate {
|
||||
public:
|
||||
struct Character {
|
||||
uint32_t value;
|
||||
bool hasBeenRead;
|
||||
};
|
||||
|
||||
RealTimeTextChatRoomPrivate () = default;
|
||||
|
||||
void realtimeTextReceived (uint32_t character, LinphoneCall *call);
|
||||
void realtimeTextReceived (uint32_t character, const std::shared_ptr<Call> &call);
|
||||
void sendChatMessage (const std::shared_ptr<ChatMessage> &chatMessage) override;
|
||||
void setCall (const std::shared_ptr<Call> &value) { call = value; }
|
||||
|
||||
LinphoneCall *call = nullptr;
|
||||
std::list<LinphoneChatMessageCharacter *> receivedRttCharacters;
|
||||
std::weak_ptr<Call> call;
|
||||
std::list<Character> receivedRttCharacters;
|
||||
std::shared_ptr<ChatMessage> pendingMessage = nullptr;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "c-wrapper/c-wrapper.h"
|
||||
#include "call/call.h"
|
||||
#include "chat/chat-message/chat-message-p.h"
|
||||
#include "conference/participant.h"
|
||||
#include "core/core.h"
|
||||
|
|
@ -32,7 +33,7 @@ LINPHONE_BEGIN_NAMESPACE
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, LinphoneCall *call) {
|
||||
void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, const shared_ptr<Call> &call) {
|
||||
L_Q();
|
||||
const uint32_t new_line = 0x2028;
|
||||
const uint32_t crlf = 0x0D0A;
|
||||
|
|
@ -41,56 +42,48 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, Linp
|
|||
shared_ptr<Core> core = q->getCore();
|
||||
LinphoneCore *cCore = core->getCCore();
|
||||
|
||||
if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) {
|
||||
LinphoneChatMessageCharacter *cmc = bctbx_new0(LinphoneChatMessageCharacter, 1);
|
||||
|
||||
if (call && call->getCurrentParams()->realtimeTextEnabled()) {
|
||||
if (!pendingMessage)
|
||||
pendingMessage = q->createChatMessage("");
|
||||
|
||||
cmc->value = character;
|
||||
cmc->has_been_read = FALSE;
|
||||
Character cmc;
|
||||
cmc.value = character;
|
||||
cmc.hasBeenRead = false;
|
||||
receivedRttCharacters.push_back(cmc);
|
||||
|
||||
remoteIsComposing.push_back(q->getPeerAddress());
|
||||
linphone_core_notify_is_composing_received(cCore, L_GET_C_BACK_PTR(q));
|
||||
|
||||
if ((character == new_line) || (character == crlf) || (character == lf)) {
|
||||
/* End of message */
|
||||
// End of message
|
||||
lDebug() << "New line received, forge a message with content " << pendingMessage->getPrivate()->getText().c_str();
|
||||
// TODO: REPAIR ME.
|
||||
// pendingMessage->setFromAddress(peerAddress);
|
||||
// pendingMessage->setToAddress(
|
||||
// Address(
|
||||
// linphone_call_get_dest_proxy(call)
|
||||
// ? linphone_address_as_string(linphone_call_get_dest_proxy(call)->identity_address)
|
||||
// : linphone_core_get_identity(cCore)
|
||||
// )
|
||||
// );
|
||||
pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered);
|
||||
pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming);
|
||||
pendingMessage->getPrivate()->setTime(::ms_time(0));
|
||||
|
||||
if (lp_config_get_int(linphone_core_get_config(cCore), "misc", "store_rtt_messages", 1) == 1)
|
||||
pendingMessage->getPrivate()->storeInDb();
|
||||
|
||||
onChatMessageReceived(pendingMessage);
|
||||
pendingMessage = nullptr;
|
||||
for (auto &rttChars : receivedRttCharacters)
|
||||
ms_free(rttChars);
|
||||
receivedRttCharacters.clear();
|
||||
} else {
|
||||
char *value = Utils::utf8ToChar(character);
|
||||
char *text = (char *)pendingMessage->getPrivate()->getText().c_str();
|
||||
pendingMessage->getPrivate()->setText(ms_strcat_printf(text, value));
|
||||
string text(pendingMessage->getPrivate()->getText());
|
||||
text += string(value);
|
||||
pendingMessage->getPrivate()->setText(text);
|
||||
lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << pendingMessage->getPrivate()->getText();
|
||||
delete value;
|
||||
delete[] value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RealTimeTextChatRoomPrivate::sendChatMessage (const shared_ptr<ChatMessage> &chatMessage) {
|
||||
if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) {
|
||||
uint32_t new_line = 0x2028;
|
||||
chatMessage->putCharacter(new_line);
|
||||
L_Q();
|
||||
shared_ptr<Call> call = q->getCall();
|
||||
if (call && call->getCurrentParams()->realtimeTextEnabled()) {
|
||||
uint32_t newLine = 0x2028;
|
||||
chatMessage->putCharacter(newLine);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,26 +92,16 @@ void RealTimeTextChatRoomPrivate::sendChatMessage (const shared_ptr<ChatMessage>
|
|||
RealTimeTextChatRoom::RealTimeTextChatRoom (const shared_ptr<Core> &core, const ChatRoomId &chatRoomId) :
|
||||
BasicChatRoom(*new RealTimeTextChatRoomPrivate, core, chatRoomId) {}
|
||||
|
||||
RealTimeTextChatRoom::~RealTimeTextChatRoom () {
|
||||
L_D();
|
||||
|
||||
if (!d->receivedRttCharacters.empty())
|
||||
for (auto &rttChars : d->receivedRttCharacters)
|
||||
bctbx_free(rttChars);
|
||||
}
|
||||
|
||||
RealTimeTextChatRoom::CapabilitiesMask RealTimeTextChatRoom::getCapabilities () const {
|
||||
return BasicChatRoom::getCapabilities() | Capabilities::RealTimeText;
|
||||
}
|
||||
|
||||
uint32_t RealTimeTextChatRoom::getChar () const {
|
||||
L_D();
|
||||
if (!d->receivedRttCharacters.empty()) {
|
||||
for (auto &cmc : d->receivedRttCharacters) {
|
||||
if (!cmc->has_been_read) {
|
||||
cmc->has_been_read = TRUE;
|
||||
return cmc->value;
|
||||
}
|
||||
for (const auto &cmc : d->receivedRttCharacters) {
|
||||
if (!cmc.hasBeenRead) {
|
||||
const_cast<RealTimeTextChatRoomPrivate::Character *>(&cmc)->hasBeenRead = true;
|
||||
return cmc.value;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -126,9 +109,9 @@ uint32_t RealTimeTextChatRoom::getChar () const {
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
LinphoneCall *RealTimeTextChatRoom::getCall () const {
|
||||
shared_ptr<Call> RealTimeTextChatRoom::getCall () const {
|
||||
L_D();
|
||||
return d->call;
|
||||
return d->call.lock();
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -26,18 +26,20 @@
|
|||
|
||||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
class Call;
|
||||
class RealTimeTextChatRoomPrivate;
|
||||
|
||||
class LINPHONE_PUBLIC RealTimeTextChatRoom : public BasicChatRoom {
|
||||
friend class CallPrivate;
|
||||
friend class CorePrivate;
|
||||
|
||||
public:
|
||||
~RealTimeTextChatRoom ();
|
||||
~RealTimeTextChatRoom () = default;
|
||||
|
||||
CapabilitiesMask getCapabilities () const override;
|
||||
|
||||
uint32_t getChar () const;
|
||||
LinphoneCall *getCall () const;
|
||||
std::shared_ptr<Call> getCall () const;
|
||||
|
||||
private:
|
||||
RealTimeTextChatRoom (const std::shared_ptr<Core> &core, const ChatRoomId &chatRoomId);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "chat-room-p.h"
|
||||
#include "server-group-chat-room.h"
|
||||
#include "conference/participant-device.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
|
@ -41,6 +42,10 @@ public:
|
|||
std::shared_ptr<Participant> findFilteredParticipant (const std::shared_ptr<const CallSession> &session) const;
|
||||
std::shared_ptr<Participant> findFilteredParticipant (const IdentityAddress &participantAddress) const;
|
||||
|
||||
ParticipantDevice::State getParticipantDeviceState (const std::shared_ptr<const ParticipantDevice> &device) const;
|
||||
void setParticipantDeviceState (const std::shared_ptr<ParticipantDevice> &device, ParticipantDevice::State state);
|
||||
|
||||
void acceptSession (const std::shared_ptr<CallSession> &session);
|
||||
void confirmCreation ();
|
||||
void confirmJoining (SalCallOp *op);
|
||||
void confirmRecreation (SalCallOp *op);
|
||||
|
|
@ -79,6 +84,7 @@ private:
|
|||
bool isAdminLeft () const;
|
||||
void queueMessage (const std::shared_ptr<Message> &message);
|
||||
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);
|
||||
|
||||
|
|
@ -89,7 +95,7 @@ private:
|
|||
|
||||
// CallSessionListener
|
||||
void onCallSessionStateChanged (
|
||||
const std::shared_ptr<const CallSession> &session,
|
||||
const std::shared_ptr<CallSession> &session,
|
||||
CallSession::State newState,
|
||||
const std::string &message
|
||||
) override;
|
||||
|
|
|
|||
|
|
@ -42,8 +42,18 @@ shared_ptr<Participant> ServerGroupChatRoomPrivate::findFilteredParticipant (con
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ParticipantDevice::State ServerGroupChatRoomPrivate::getParticipantDeviceState (const shared_ptr<const ParticipantDevice> &device) const {
|
||||
return device->getState();
|
||||
}
|
||||
|
||||
void ServerGroupChatRoomPrivate::setParticipantDeviceState (const shared_ptr<ParticipantDevice> &device, ParticipantDevice::State state) {
|
||||
device->setState(state);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ServerGroupChatRoomPrivate::acceptSession (const shared_ptr<CallSession> &session) {}
|
||||
|
||||
void ServerGroupChatRoomPrivate::confirmCreation () {}
|
||||
|
||||
void ServerGroupChatRoomPrivate::confirmJoining (SalCallOp *) {}
|
||||
|
|
@ -80,23 +90,25 @@ LinphoneReason ServerGroupChatRoomPrivate::onSipMessageReceived (SalOp *, const
|
|||
|
||||
void ServerGroupChatRoomPrivate::designateAdmin () {}
|
||||
|
||||
void ServerGroupChatRoomPrivate::dispatchMessage (const std::shared_ptr<Message> &message, const std::string &uri) {}
|
||||
void ServerGroupChatRoomPrivate::dispatchMessage (const shared_ptr<Message> &message, const string &uri) {}
|
||||
|
||||
void ServerGroupChatRoomPrivate::finalizeCreation () {}
|
||||
|
||||
void ServerGroupChatRoomPrivate::inviteDevice (const std::shared_ptr<ParticipantDevice> &device) {}
|
||||
void ServerGroupChatRoomPrivate::inviteDevice (const shared_ptr<ParticipantDevice> &device) {}
|
||||
|
||||
bool ServerGroupChatRoomPrivate::isAdminLeft () const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ServerGroupChatRoomPrivate::queueMessage (const std::shared_ptr<Message> &message) {}
|
||||
void ServerGroupChatRoomPrivate::queueMessage (const shared_ptr<Message> &message) {}
|
||||
|
||||
void ServerGroupChatRoomPrivate::queueMessage (const std::shared_ptr<Message> &msg, const IdentityAddress &deviceAddress) {}
|
||||
void ServerGroupChatRoomPrivate::queueMessage (const shared_ptr<Message> &msg, const IdentityAddress &deviceAddress) {}
|
||||
|
||||
void ServerGroupChatRoomPrivate::removeNonPresentParticipants (const list <IdentityAddress> &compatibleParticipants) {}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ServerGroupChatRoomPrivate::onParticipantDeviceLeft (const std::shared_ptr<const CallSession> &session) {}
|
||||
void ServerGroupChatRoomPrivate::onParticipantDeviceLeft (const shared_ptr<const CallSession> &session) {}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -109,7 +121,7 @@ void ServerGroupChatRoomPrivate::onChatRoomDeleteRequested (const shared_ptr<Abs
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ServerGroupChatRoomPrivate::onCallSessionStateChanged (
|
||||
const shared_ptr<const CallSession> &,
|
||||
const shared_ptr<CallSession> &,
|
||||
CallSession::State,
|
||||
const string &
|
||||
) {}
|
||||
|
|
|
|||
|
|
@ -364,24 +364,24 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
|
|||
message->removeContent(*fileContent);
|
||||
message->addContent(*fileTransferContent);
|
||||
|
||||
message->updateState(ChatMessage::State::FileTransferDone);
|
||||
message->getPrivate()->setState(ChatMessage::State::FileTransferDone);
|
||||
releaseHttpRequest();
|
||||
message->getPrivate()->send();
|
||||
fileUploadEndBackgroundTask();
|
||||
} else {
|
||||
lWarning() << "Received empty response from server, file transfer failed";
|
||||
message->updateState(ChatMessage::State::NotDelivered);
|
||||
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
|
||||
releaseHttpRequest();
|
||||
fileUploadEndBackgroundTask();
|
||||
}
|
||||
} else if (code == 400) {
|
||||
lWarning() << "Received HTTP code response " << code << " for file transfer, probably meaning file is too large";
|
||||
message->updateState(ChatMessage::State::FileTransferError);
|
||||
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
|
||||
releaseHttpRequest();
|
||||
fileUploadEndBackgroundTask();
|
||||
} else {
|
||||
lWarning() << "Unhandled HTTP code response " << code << " for file transfer";
|
||||
message->updateState(ChatMessage::State::NotDelivered);
|
||||
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
|
||||
releaseHttpRequest();
|
||||
fileUploadEndBackgroundTask();
|
||||
}
|
||||
|
|
@ -398,7 +398,7 @@ void FileTransferChatMessageModifier::processIoErrorUpload (const belle_sip_io_e
|
|||
shared_ptr<ChatMessage> message = chatMessage.lock();
|
||||
if (!message)
|
||||
return;
|
||||
message->updateState(ChatMessage::State::NotDelivered);
|
||||
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
|
||||
releaseHttpRequest();
|
||||
}
|
||||
|
||||
|
|
@ -412,7 +412,7 @@ void FileTransferChatMessageModifier::processAuthRequestedUpload (const belle_si
|
|||
shared_ptr<ChatMessage> message = chatMessage.lock();
|
||||
if (!message)
|
||||
return;
|
||||
message->updateState(ChatMessage::State::NotDelivered);
|
||||
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
|
||||
releaseHttpRequest();
|
||||
}
|
||||
|
||||
|
|
@ -844,7 +844,7 @@ void FileTransferChatMessageModifier::processAuthRequestedDownload (const belle_
|
|||
shared_ptr<ChatMessage> message = chatMessage.lock();
|
||||
if (!message)
|
||||
return;
|
||||
message->updateState(ChatMessage::State::FileTransferError);
|
||||
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
|
||||
releaseHttpRequest();
|
||||
}
|
||||
|
||||
|
|
@ -858,7 +858,7 @@ void FileTransferChatMessageModifier::processIoErrorDownload (const belle_sip_io
|
|||
shared_ptr<ChatMessage> message = chatMessage.lock();
|
||||
if (!message)
|
||||
return;
|
||||
message->updateState(ChatMessage::State::FileTransferError);
|
||||
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
|
||||
releaseHttpRequest();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ ChatMessageModifier::Result MultipartChatMessageModifier::encode (
|
|||
multipartMessage << "--";
|
||||
|
||||
Content newContent;
|
||||
ContentType newContentType("multipart/mixed");
|
||||
ContentType newContentType(ContentType::Multipart);
|
||||
newContentType.setParameter("boundary=" + boundary);
|
||||
newContent.setContentType(newContentType);
|
||||
newContent.setBody(multipartMessage.str());
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "chat/chat-message/chat-message.h"
|
||||
#include "chat/chat-message/chat-message-p.h"
|
||||
#include "chat/chat-room/chat-room.h"
|
||||
#include "core/core.h"
|
||||
#include "logger/logger.h"
|
||||
|
|
@ -40,7 +40,8 @@ string Imdn::createXml (const string &id, time_t time, Imdn::Type imdnType, Linp
|
|||
char *datetime = nullptr;
|
||||
|
||||
// Check that the chat message has a message id.
|
||||
if (id.empty()) return nullptr;
|
||||
if (id.empty())
|
||||
return content;
|
||||
|
||||
buf = xmlBufferCreate();
|
||||
if (buf == nullptr) {
|
||||
|
|
@ -132,18 +133,18 @@ string Imdn::createXml (const string &id, time_t time, Imdn::Type imdnType, Linp
|
|||
return content;
|
||||
}
|
||||
|
||||
void Imdn::parse (ChatRoom &cr, const string &text) {
|
||||
void Imdn::parse (const shared_ptr<ChatMessage> &chatMessage) {
|
||||
xmlparsing_context_t *xmlCtx = linphone_xmlparsing_context_new();
|
||||
xmlSetGenericErrorFunc(xmlCtx, linphone_xmlparsing_genericxml_error);
|
||||
xmlCtx->doc = xmlReadDoc((const unsigned char *)text.c_str(), 0, nullptr, 0);
|
||||
xmlCtx->doc = xmlReadDoc((const unsigned char *)chatMessage->getPrivate()->getText().c_str(), 0, nullptr, 0);
|
||||
if (xmlCtx->doc)
|
||||
parse(cr, xmlCtx);
|
||||
parse(chatMessage, xmlCtx);
|
||||
else
|
||||
lWarning() << "Wrongly formatted IMDN XML: " << xmlCtx->errorBuffer;
|
||||
linphone_xmlparsing_context_destroy(xmlCtx);
|
||||
}
|
||||
|
||||
void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) {
|
||||
void Imdn::parse (const shared_ptr<ChatMessage> &imdnMessage, xmlparsing_context_t *xmlCtx) {
|
||||
char xpathStr[MAX_XPATH_LENGTH];
|
||||
char *messageIdStr = nullptr;
|
||||
char *datetimeStr = nullptr;
|
||||
|
|
@ -163,11 +164,13 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) {
|
|||
}
|
||||
|
||||
if (messageIdStr && datetimeStr) {
|
||||
shared_ptr<ChatMessage> cm = cr.findChatMessage(messageIdStr, ChatMessage::Direction::Outgoing);
|
||||
shared_ptr<AbstractChatRoom> cr = imdnMessage->getChatRoom();
|
||||
shared_ptr<ChatMessage> cm = cr->findChatMessage(messageIdStr, ChatMessage::Direction::Outgoing);
|
||||
const IdentityAddress &participantAddress = imdnMessage->getFromAddress().getAddressWithoutGruu();
|
||||
if (!cm) {
|
||||
lWarning() << "Received IMDN for unknown message " << messageIdStr;
|
||||
} else {
|
||||
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(cr.getCore()->getCCore());
|
||||
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(cr->getCore()->getCCore());
|
||||
snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:delivery-notification/imdn:status", imdnPrefix.c_str());
|
||||
xmlXPathObjectPtr deliveryStatusObject = linphone_get_xml_xpath_object_for_node_list(xmlCtx, xpathStr);
|
||||
snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:display-notification/imdn:status", imdnPrefix.c_str());
|
||||
|
|
@ -177,9 +180,9 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) {
|
|||
xmlNodePtr node = deliveryStatusObject->nodesetval->nodeTab[0];
|
||||
if (node->children && node->children->name) {
|
||||
if (strcmp((const char *)node->children->name, "delivered") == 0) {
|
||||
cm->updateState(ChatMessage::State::DeliveredToUser);
|
||||
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::DeliveredToUser);
|
||||
} else if (strcmp((const char *)node->children->name, "error") == 0) {
|
||||
cm->updateState(ChatMessage::State::NotDelivered);
|
||||
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::NotDelivered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -190,7 +193,7 @@ void Imdn::parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx) {
|
|||
xmlNodePtr node = displayStatusObject->nodesetval->nodeTab[0];
|
||||
if (node->children && node->children->name) {
|
||||
if (strcmp((const char *)node->children->name, "displayed") == 0) {
|
||||
cm->updateState(ChatMessage::State::Displayed);
|
||||
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::Displayed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ public:
|
|||
};
|
||||
|
||||
static std::string createXml (const std::string &id, time_t time, Imdn::Type imdnType, LinphoneReason reason);
|
||||
static void parse (ChatRoom &cr, const std::string &content);
|
||||
static void parse (const std::shared_ptr<ChatMessage> &chatMessage);
|
||||
|
||||
private:
|
||||
static void parse (ChatRoom &cr, xmlparsing_context_t *xmlCtx);
|
||||
static void parse (const std::shared_ptr<ChatMessage> &chatMessage, xmlparsing_context_t *xmlCtx);
|
||||
|
||||
private:
|
||||
static const std::string imdnPrefix;
|
||||
|
|
|
|||
|
|
@ -61,11 +61,8 @@ void Conference::addParticipants (const list<IdentityAddress> &addresses, const
|
|||
list<IdentityAddress> sortedAddresses(addresses);
|
||||
sortedAddresses.sort();
|
||||
sortedAddresses.unique();
|
||||
for (const auto &addr: sortedAddresses) {
|
||||
shared_ptr<Participant> participant = findParticipant(addr);
|
||||
if (!participant)
|
||||
addParticipant(addr, params, hasMedia);
|
||||
}
|
||||
for (const auto &addr: sortedAddresses)
|
||||
addParticipant(addr, params, hasMedia);
|
||||
}
|
||||
|
||||
bool Conference::canHandleParticipants () const {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <sstream>
|
||||
|
||||
#include "linphone/utils/algorithm.h"
|
||||
#include "linphone/utils/utils.h"
|
||||
|
||||
#include "conference/remote-conference.h"
|
||||
|
|
@ -45,135 +46,150 @@ using namespace Xsd::ConferenceInfo;
|
|||
void RemoteConferenceEventHandlerPrivate::simpleNotifyReceived (const string &xmlBody) {
|
||||
istringstream data(xmlBody);
|
||||
unique_ptr<ConferenceType> confInfo = parseConferenceInfo(data, Xsd::XmlSchema::Flags::dont_validate);
|
||||
time_t tm = time(nullptr);
|
||||
if (confInfo->getConferenceDescription()->getFreeText().present())
|
||||
tm = static_cast<time_t>(Utils::stoll(confInfo->getConferenceDescription()->getFreeText().get()));
|
||||
|
||||
bool isFullState = (confInfo->getState() == StateType::full);
|
||||
|
||||
ConferenceListener *confListener = static_cast<ConferenceListener *>(conf);
|
||||
|
||||
IdentityAddress entityAddress(confInfo->getEntity().c_str());
|
||||
if (entityAddress == chatRoomId.getPeerAddress()) {
|
||||
if (confInfo->getVersion().present())
|
||||
lastNotify = confInfo->getVersion().get();
|
||||
if (entityAddress != chatRoomId.getPeerAddress())
|
||||
return;
|
||||
|
||||
if (confInfo->getConferenceDescription().present()) {
|
||||
if (confInfo->getConferenceDescription().get().getSubject().present() &&
|
||||
!confInfo->getConferenceDescription().get().getSubject().get().empty()
|
||||
) {
|
||||
confListener->onSubjectChanged(
|
||||
make_shared<ConferenceSubjectEvent>(
|
||||
tm,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
confInfo->getConferenceDescription().get().getSubject().get()
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
}
|
||||
if (confInfo->getConferenceDescription().get().getKeywords().present()
|
||||
&& !confInfo->getConferenceDescription().get().getKeywords().get().empty()
|
||||
) {
|
||||
KeywordsType xmlKeywords = confInfo->getConferenceDescription().get().getKeywords().get();
|
||||
vector<string> keywords;
|
||||
for (const auto &k : xmlKeywords)
|
||||
keywords.push_back(k);
|
||||
confListener->onConferenceKeywordsChanged(keywords);
|
||||
}
|
||||
}
|
||||
auto &confDescription = confInfo->getConferenceDescription();
|
||||
|
||||
if (!confInfo->getUsers().present())
|
||||
return;
|
||||
|
||||
for (const auto &user : confInfo->getUsers()->getUser()) {
|
||||
LinphoneAddress *cAddr = linphone_core_interpret_url(conf->getCore()->getCCore(), user.getEntity()->c_str());
|
||||
char *cAddrStr = linphone_address_as_string(cAddr);
|
||||
Address addr(cAddrStr);
|
||||
bctbx_free(cAddrStr);
|
||||
if (user.getState() == StateType::deleted) {
|
||||
confListener->onParticipantRemoved(
|
||||
make_shared<ConferenceParticipantEvent>(
|
||||
EventLog::Type::ConferenceParticipantRemoved,
|
||||
tm,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
} else {
|
||||
if (user.getState() == StateType::full) {
|
||||
confListener->onParticipantAdded(
|
||||
make_shared<ConferenceParticipantEvent>(
|
||||
EventLog::Type::ConferenceParticipantAdded,
|
||||
tm,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
}
|
||||
|
||||
if (user.getRoles()) {
|
||||
bool isAdmin = false;
|
||||
for (const auto &entry : user.getRoles()->getEntry()) {
|
||||
if (entry == "admin") {
|
||||
isAdmin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
confListener->onParticipantSetAdmin(
|
||||
make_shared<ConferenceParticipantEvent>(
|
||||
isAdmin ? EventLog::Type::ConferenceParticipantSetAdmin : EventLog::Type::ConferenceParticipantUnsetAdmin,
|
||||
tm,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
}
|
||||
|
||||
for (const auto &endpoint : user.getEndpoint()) {
|
||||
if (!endpoint.getEntity().present())
|
||||
break;
|
||||
|
||||
Address gruu(endpoint.getEntity().get());
|
||||
if (endpoint.getState() == StateType::deleted) {
|
||||
confListener->onParticipantDeviceRemoved(
|
||||
make_shared<ConferenceParticipantDeviceEvent>(
|
||||
EventLog::Type::ConferenceParticipantDeviceRemoved,
|
||||
tm,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr,
|
||||
gruu
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
} else if (endpoint.getState() == StateType::full) {
|
||||
confListener->onParticipantDeviceAdded(
|
||||
make_shared<ConferenceParticipantDeviceEvent>(
|
||||
EventLog::Type::ConferenceParticipantDeviceAdded,
|
||||
tm,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr,
|
||||
gruu
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
linphone_address_unref(cAddr);
|
||||
}
|
||||
|
||||
if (isFullState)
|
||||
confListener->onFirstNotifyReceived(chatRoomId.getPeerAddress());
|
||||
// 1. Compute event time.
|
||||
time_t creationTime = time(nullptr);
|
||||
{
|
||||
auto &freeText = confDescription->getFreeText();
|
||||
if (freeText.present())
|
||||
creationTime = static_cast<time_t>(Utils::stoll(freeText.get()));
|
||||
}
|
||||
|
||||
// 2. Update last notify.
|
||||
{
|
||||
auto &version = confInfo->getVersion();
|
||||
if (version.present())
|
||||
lastNotify = version.get();
|
||||
}
|
||||
|
||||
bool isFullState = confInfo->getState() == StateType::full;
|
||||
ConferenceListener *confListener = static_cast<ConferenceListener *>(conf);
|
||||
|
||||
// 3. Notify subject and keywords.
|
||||
if (confDescription.present()) {
|
||||
auto &subject = confDescription.get().getSubject();
|
||||
if (subject.present() && !subject.get().empty())
|
||||
confListener->onSubjectChanged(
|
||||
make_shared<ConferenceSubjectEvent>(
|
||||
creationTime,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
subject.get()
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
|
||||
auto &keywords = confDescription.get().getKeywords();
|
||||
if (keywords.present() && !keywords.get().empty()) {
|
||||
KeywordsType xmlKeywords = keywords.get();
|
||||
confListener->onConferenceKeywordsChanged(
|
||||
vector<string>(xmlKeywords.begin(), xmlKeywords.end())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
auto &users = confInfo->getUsers();
|
||||
if (!users.present())
|
||||
return;
|
||||
|
||||
// 4. Notify changes on users.
|
||||
for (auto &user : users->getUser()) {
|
||||
LinphoneAddress *cAddr = linphone_core_interpret_url(conf->getCore()->getCCore(), user.getEntity()->c_str());
|
||||
char *cAddrStr = linphone_address_as_string(cAddr);
|
||||
linphone_address_unref(cAddr);
|
||||
|
||||
Address addr(cAddrStr);
|
||||
bctbx_free(cAddrStr);
|
||||
|
||||
StateType state = user.getState();
|
||||
|
||||
if (state == StateType::deleted) {
|
||||
confListener->onParticipantRemoved(
|
||||
make_shared<ConferenceParticipantEvent>(
|
||||
EventLog::Type::ConferenceParticipantRemoved,
|
||||
creationTime,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state == StateType::full)
|
||||
confListener->onParticipantAdded(
|
||||
make_shared<ConferenceParticipantEvent>(
|
||||
EventLog::Type::ConferenceParticipantAdded,
|
||||
creationTime,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
|
||||
auto &roles = user.getRoles();
|
||||
if (roles) {
|
||||
auto &entry = roles->getEntry();
|
||||
confListener->onParticipantSetAdmin(
|
||||
make_shared<ConferenceParticipantEvent>(
|
||||
find(entry, "admin") != entry.end()
|
||||
? EventLog::Type::ConferenceParticipantSetAdmin
|
||||
: EventLog::Type::ConferenceParticipantUnsetAdmin,
|
||||
creationTime,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
}
|
||||
|
||||
for (const auto &endpoint : user.getEndpoint()) {
|
||||
if (!endpoint.getEntity().present())
|
||||
break;
|
||||
|
||||
Address gruu(endpoint.getEntity().get());
|
||||
StateType state = endpoint.getState();
|
||||
|
||||
if (state == StateType::deleted) {
|
||||
confListener->onParticipantDeviceRemoved(
|
||||
make_shared<ConferenceParticipantDeviceEvent>(
|
||||
EventLog::Type::ConferenceParticipantDeviceRemoved,
|
||||
creationTime,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr,
|
||||
gruu
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
} else if (state == StateType::full) {
|
||||
confListener->onParticipantDeviceAdded(
|
||||
make_shared<ConferenceParticipantDeviceEvent>(
|
||||
EventLog::Type::ConferenceParticipantDeviceAdded,
|
||||
creationTime,
|
||||
chatRoomId,
|
||||
lastNotify,
|
||||
addr,
|
||||
gruu
|
||||
),
|
||||
isFullState
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isFullState)
|
||||
confListener->onFirstNotifyReceived(chatRoomId.getPeerAddress());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#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"
|
||||
|
||||
|
|
@ -46,8 +47,10 @@ LocalConference::~LocalConference () {
|
|||
void LocalConference::addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) {
|
||||
L_D();
|
||||
shared_ptr<Participant> participant = findParticipant(addr);
|
||||
if (participant)
|
||||
if (participant) {
|
||||
lInfo() << "Not adding participant '" << addr.asString() << "' because it is already a participant of the LocalConference";
|
||||
return;
|
||||
}
|
||||
participant = make_shared<Participant>(addr);
|
||||
participant->getPrivate()->createSession(*this, params, hasMedia, d->listener);
|
||||
d->participants.push_back(participant);
|
||||
|
|
|
|||
|
|
@ -29,9 +29,8 @@ LINPHONE_BEGIN_NAMESPACE
|
|||
|
||||
ParticipantDevice::ParticipantDevice () {}
|
||||
|
||||
ParticipantDevice::ParticipantDevice (const IdentityAddress &gruu) {
|
||||
mGruu = gruu;
|
||||
}
|
||||
ParticipantDevice::ParticipantDevice (const Participant *participant, const IdentityAddress &gruu)
|
||||
: mParticipant(participant), mGruu(gruu) {}
|
||||
|
||||
ParticipantDevice::~ParticipantDevice () {
|
||||
if (mConferenceSubscribeEvent)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "address/identity-address.h"
|
||||
|
||||
#include "linphone/types.h"
|
||||
#include "linphone/utils/general.h"
|
||||
|
||||
|
|
@ -31,6 +32,7 @@
|
|||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
class CallSession;
|
||||
class Participant;
|
||||
|
||||
class ParticipantDevice {
|
||||
public:
|
||||
|
|
@ -42,12 +44,13 @@ public:
|
|||
};
|
||||
|
||||
ParticipantDevice ();
|
||||
explicit ParticipantDevice (const IdentityAddress &gruu);
|
||||
explicit ParticipantDevice (const 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; }
|
||||
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; }
|
||||
|
|
@ -60,6 +63,7 @@ public:
|
|||
bool isValid () const { return mGruu.isValid(); }
|
||||
|
||||
private:
|
||||
const Participant *mParticipant = nullptr;
|
||||
IdentityAddress mGruu;
|
||||
std::shared_ptr<CallSession> mSession;
|
||||
LinphoneEvent *mConferenceSubscribeEvent = nullptr;
|
||||
|
|
|
|||
|
|
@ -47,10 +47,11 @@ shared_ptr<CallSession> ParticipantPrivate::createSession (
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
shared_ptr<ParticipantDevice> ParticipantPrivate::addDevice (const IdentityAddress &gruu) {
|
||||
L_Q();
|
||||
shared_ptr<ParticipantDevice> device = findDevice(gruu);
|
||||
if (device)
|
||||
return device;
|
||||
device = make_shared<ParticipantDevice>(gruu);
|
||||
device = make_shared<ParticipantDevice>(q, gruu);
|
||||
devices.push_back(device);
|
||||
return device;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "handlers/remote-conference-event-handler.h"
|
||||
#include "logger/logger.h"
|
||||
#include "participant-p.h"
|
||||
#include "remote-conference-p.h"
|
||||
#include "xml/resource-lists.h"
|
||||
|
|
@ -47,8 +48,10 @@ RemoteConference::~RemoteConference () {
|
|||
void RemoteConference::addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) {
|
||||
L_D();
|
||||
shared_ptr<Participant> participant = findParticipant(addr);
|
||||
if (participant)
|
||||
if (participant) {
|
||||
lInfo() << "Not adding participant '" << addr.asString() << "' because it is already a participant of the RemoteConference";
|
||||
return;
|
||||
}
|
||||
participant = make_shared<Participant>(addr);
|
||||
participant->getPrivate()->createSession(*this, params, hasMedia, d->listener);
|
||||
d->participants.push_back(participant);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include "conference/session/call-session.h"
|
||||
|
||||
#include <mediastreamer2/msrtt4103.h>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
|
@ -32,49 +34,51 @@ class LINPHONE_PUBLIC CallSessionListener {
|
|||
public:
|
||||
virtual ~CallSessionListener() = default;
|
||||
|
||||
virtual void onAckBeingSent (const std::shared_ptr<const CallSession> &session, LinphoneHeaders *headers) {}
|
||||
virtual void onAckReceived (const std::shared_ptr<const CallSession> &session, LinphoneHeaders *headers) {}
|
||||
virtual void onBackgroundTaskToBeStarted (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onBackgroundTaskToBeStopped (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual bool onCallSessionAccepted (const std::shared_ptr<const CallSession> &session) { return false; }
|
||||
virtual void onCallSessionConferenceStreamStarting (const std::shared_ptr<const CallSession> &session, bool mute) {}
|
||||
virtual void onCallSessionConferenceStreamStopping (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onCallSessionEarlyFailed (const std::shared_ptr<const CallSession> &session, LinphoneErrorInfo *ei) {}
|
||||
virtual void onCallSessionSetReleased (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onCallSessionSetTerminated (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onCallSessionStartReferred (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onCallSessionStateChanged (const std::shared_ptr<const CallSession> &session, CallSession::State state, const std::string &message) {}
|
||||
virtual void onCallSessionTransferStateChanged (const std::shared_ptr<const CallSession> &session, CallSession::State state) {}
|
||||
virtual void onCheckForAcceptation (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onDtmfReceived (const std::shared_ptr<const CallSession> &session, char dtmf) {}
|
||||
virtual void onIncomingCallSessionNotified (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onIncomingCallSessionStarted (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onIncomingCallSessionTimeoutCheck (const std::shared_ptr<const CallSession> &session, int elapsed, bool oneSecondElapsed) {}
|
||||
virtual void onInfoReceived (const std::shared_ptr<const CallSession> &session, const LinphoneInfoMessage *im) {}
|
||||
virtual void onNoMediaTimeoutCheck (const std::shared_ptr<const CallSession> &session, bool oneSecondElapsed) {}
|
||||
virtual void onAckBeingSent (const std::shared_ptr<CallSession> &session, LinphoneHeaders *headers) {}
|
||||
virtual void onAckReceived (const std::shared_ptr<CallSession> &session, LinphoneHeaders *headers) {}
|
||||
virtual void onBackgroundTaskToBeStarted (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onBackgroundTaskToBeStopped (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual bool onCallSessionAccepted (const std::shared_ptr<CallSession> &session) { return false; }
|
||||
virtual void onCallSessionConferenceStreamStarting (const std::shared_ptr<CallSession> &session, bool mute) {}
|
||||
virtual void onCallSessionConferenceStreamStopping (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onCallSessionEarlyFailed (const std::shared_ptr<CallSession> &session, LinphoneErrorInfo *ei) {}
|
||||
virtual void onCallSessionSetReleased (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onCallSessionSetTerminated (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onCallSessionStartReferred (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onCallSessionStateChanged (const std::shared_ptr<CallSession> &session, CallSession::State state, const std::string &message) {}
|
||||
virtual void onCallSessionTransferStateChanged (const std::shared_ptr<CallSession> &session, CallSession::State state) {}
|
||||
virtual void onCheckForAcceptation (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onDtmfReceived (const std::shared_ptr<CallSession> &session, char dtmf) {}
|
||||
virtual void onIncomingCallSessionNotified (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onIncomingCallSessionStarted (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onIncomingCallSessionTimeoutCheck (const std::shared_ptr<CallSession> &session, int elapsed, bool oneSecondElapsed) {}
|
||||
virtual void onInfoReceived (const std::shared_ptr<CallSession> &session, const LinphoneInfoMessage *im) {}
|
||||
virtual void onNoMediaTimeoutCheck (const std::shared_ptr<CallSession> &session, bool oneSecondElapsed) {}
|
||||
|
||||
virtual void onEncryptionChanged (const std::shared_ptr<const CallSession> &session, bool activated, const std::string &authToken) {}
|
||||
virtual void onEncryptionChanged (const std::shared_ptr<CallSession> &session, bool activated, const std::string &authToken) {}
|
||||
|
||||
virtual void onCallSessionStateChangedForReporting (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onRtcpUpdateForReporting (const std::shared_ptr<const CallSession> &session, SalStreamType type) {}
|
||||
virtual void onStatsUpdated (const std::shared_ptr<const CallSession> &session, const LinphoneCallStats *stats) {}
|
||||
virtual void onUpdateMediaInfoForReporting (const std::shared_ptr<const CallSession> &session, int statsType) {}
|
||||
virtual void onCallSessionStateChangedForReporting (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onRtcpUpdateForReporting (const std::shared_ptr<CallSession> &session, SalStreamType type) {}
|
||||
virtual void onStatsUpdated (const std::shared_ptr<CallSession> &session, const LinphoneCallStats *stats) {}
|
||||
virtual void onUpdateMediaInfoForReporting (const std::shared_ptr<CallSession> &session, int statsType) {}
|
||||
|
||||
virtual void onResetCurrentSession (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onSetCurrentSession (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onResetCurrentSession (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onSetCurrentSession (const std::shared_ptr<CallSession> &session) {}
|
||||
|
||||
virtual void onFirstVideoFrameDecoded (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onResetFirstVideoFrameDecoded (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onFirstVideoFrameDecoded (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onResetFirstVideoFrameDecoded (const std::shared_ptr<CallSession> &session) {}
|
||||
|
||||
virtual void onPlayErrorTone (const std::shared_ptr<const CallSession> &session, LinphoneReason reason) {}
|
||||
virtual void onRingbackToneRequested (const std::shared_ptr<const CallSession> &session, bool requested) {}
|
||||
virtual void onStartRinging (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onStopRinging (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onStopRingingIfInCall (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onStopRingingIfNeeded (const std::shared_ptr<const CallSession> &session) {}
|
||||
virtual void onPlayErrorTone (const std::shared_ptr<CallSession> &session, LinphoneReason reason) {}
|
||||
virtual void onRingbackToneRequested (const std::shared_ptr<CallSession> &session, bool requested) {}
|
||||
virtual void onStartRinging (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onStopRinging (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onStopRingingIfInCall (const std::shared_ptr<CallSession> &session) {}
|
||||
virtual void onStopRingingIfNeeded (const std::shared_ptr<CallSession> &session) {}
|
||||
|
||||
virtual bool areSoundResourcesAvailable (const std::shared_ptr<const CallSession> &session) { return true; }
|
||||
virtual bool isPlayingRingbackTone (const std::shared_ptr<const CallSession> &session) { return false; }
|
||||
virtual bool areSoundResourcesAvailable (const std::shared_ptr<CallSession> &session) { return true; }
|
||||
virtual bool isPlayingRingbackTone (const std::shared_ptr<CallSession> &session) { return false; }
|
||||
|
||||
virtual void onRealTimeTextCharacterReceived (const std::shared_ptr<CallSession> &session, RealtimeTextReceivedCharacter *data) {}
|
||||
};
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ protected:
|
|||
|
||||
void accept (const CallSessionParams *params);
|
||||
virtual LinphoneStatus acceptUpdate (const CallSessionParams *csp, CallSession::State nextState, const std::string &stateInfo);
|
||||
LinphoneStatus checkForAcceptation () const;
|
||||
LinphoneStatus checkForAcceptation ();
|
||||
virtual void handleIncomingReceivedStateInIncomingNotification ();
|
||||
virtual bool isReadyForInvite () const;
|
||||
bool isUpdateAllowed (CallSession::State &nextState) const;
|
||||
|
|
|
|||
|
|
@ -521,7 +521,7 @@ LinphoneStatus CallSessionPrivate::acceptUpdate (const CallSessionParams *csp, C
|
|||
return startAcceptUpdate(nextState, stateInfo);
|
||||
}
|
||||
|
||||
LinphoneStatus CallSessionPrivate::checkForAcceptation () const {
|
||||
LinphoneStatus CallSessionPrivate::checkForAcceptation () {
|
||||
L_Q();
|
||||
switch (state) {
|
||||
case CallSession::State::IncomingReceived:
|
||||
|
|
@ -1226,6 +1226,12 @@ const LinphoneErrorInfo * CallSession::getErrorInfo () const {
|
|||
return d->ei;
|
||||
}
|
||||
|
||||
const Address& CallSession::getLocalAddress () const {
|
||||
L_D();
|
||||
return *L_GET_CPP_PTR_FROM_C_OBJECT((d->direction == LinphoneCallIncoming)
|
||||
? linphone_call_log_get_to(d->log) : linphone_call_log_get_from(d->log));
|
||||
}
|
||||
|
||||
LinphoneCallLog * CallSession::getLog () const {
|
||||
L_D();
|
||||
return d->log;
|
||||
|
|
@ -1251,10 +1257,6 @@ const Address& CallSession::getRemoteAddress () const {
|
|||
? linphone_call_log_get_from(d->log) : linphone_call_log_get_to(d->log));
|
||||
}
|
||||
|
||||
string CallSession::getRemoteAddressAsString () const {
|
||||
return getRemoteAddress().asString();
|
||||
}
|
||||
|
||||
string CallSession::getRemoteContact () const {
|
||||
L_D();
|
||||
if (d->op) {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public:
|
|||
virtual ~CallSession ();
|
||||
|
||||
LinphoneStatus accept (const CallSessionParams *csp = nullptr);
|
||||
LinphoneStatus acceptUpdate (const CallSessionParams *csp);
|
||||
LinphoneStatus acceptUpdate (const CallSessionParams *csp = nullptr);
|
||||
virtual void configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg, SalCallOp *op, const Address &from, const Address &to);
|
||||
LinphoneStatus decline (LinphoneReason reason);
|
||||
LinphoneStatus decline (const LinphoneErrorInfo *ei);
|
||||
|
|
@ -78,23 +78,23 @@ public:
|
|||
|
||||
CallSessionParams *getCurrentParams () const;
|
||||
LinphoneCallDir getDirection () const;
|
||||
const Address& getDiversionAddress () const;
|
||||
const Address &getDiversionAddress () const;
|
||||
int getDuration () const;
|
||||
const LinphoneErrorInfo * getErrorInfo () const;
|
||||
LinphoneCallLog * getLog () const;
|
||||
const Address &getLocalAddress () const;
|
||||
LinphoneCallLog *getLog () const;
|
||||
virtual const CallSessionParams *getParams () const;
|
||||
LinphoneReason getReason () const;
|
||||
std::shared_ptr<CallSession> getReferer () const;
|
||||
std::string getReferTo () const;
|
||||
const Address& getRemoteAddress () const;
|
||||
std::string getRemoteAddressAsString () const;
|
||||
const Address &getRemoteAddress () const;
|
||||
std::string getRemoteContact () const;
|
||||
const Address *getRemoteContactAddress () const;
|
||||
const CallSessionParams *getRemoteParams ();
|
||||
std::string getRemoteUserAgent () const;
|
||||
std::shared_ptr<CallSession> getReplacedCallSession () const;
|
||||
CallSession::State getState () const;
|
||||
const Address& getToAddress () const;
|
||||
const Address &getToAddress () const;
|
||||
CallSession::State getTransferState () const;
|
||||
std::shared_ptr<CallSession> getTransferTarget () const;
|
||||
std::string getToHeader (const std::string &name) const;
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ private:
|
|||
void updateRemoteSessionIdAndVer ();
|
||||
|
||||
void initStats (LinphoneCallStats *stats, LinphoneStreamType type);
|
||||
void notifyStatsUpdated (int streamIndex) const;
|
||||
void notifyStatsUpdated (int streamIndex);
|
||||
|
||||
OrtpEvQueue *getEventQueue (int streamIndex) const;
|
||||
MediaStream *getMediaStream (int streamIndex) const;
|
||||
|
|
|
|||
|
|
@ -933,7 +933,7 @@ void MediaSessionPrivate::initStats (LinphoneCallStats *stats, LinphoneStreamTyp
|
|||
_linphone_call_stats_set_ice_state(stats, LinphoneIceStateNotActivated);
|
||||
}
|
||||
|
||||
void MediaSessionPrivate::notifyStatsUpdated (int streamIndex) const {
|
||||
void MediaSessionPrivate::notifyStatsUpdated (int streamIndex) {
|
||||
L_Q();
|
||||
LinphoneCallStats *stats = nullptr;
|
||||
if (streamIndex == mainAudioStreamIndex)
|
||||
|
|
@ -2830,7 +2830,7 @@ void MediaSessionPrivate::startTextStream () {
|
|||
rtp_session_set_multicast_ttl(textStream->ms.sessions.rtp_session, tstream->ttl);
|
||||
text_stream_start(textStream, textProfile, rtpAddr, tstream->rtp_port, rtcpAddr,
|
||||
(linphone_core_rtcp_enabled(q->getCore()->getCCore()) && !isMulticast) ? (tstream->rtcp_port ? tstream->rtcp_port : tstream->rtp_port + 1) : 0, usedPt);
|
||||
ms_filter_add_notify_callback(textStream->rttsink, realTimeTextCharacterReceived, q, false);
|
||||
ms_filter_add_notify_callback(textStream->rttsink, realTimeTextCharacterReceived, this, false);
|
||||
ms_media_stream_sessions_set_encryption_mandatory(&textStream->ms.sessions, isEncryptionMandatory());
|
||||
}
|
||||
} else
|
||||
|
|
@ -3806,12 +3806,11 @@ void MediaSessionPrivate::videoStreamEventCb (const MSFilter *f, const unsigned
|
|||
#endif
|
||||
|
||||
void MediaSessionPrivate::realTimeTextCharacterReceived (MSFilter *f, unsigned int id, void *arg) {
|
||||
L_Q();
|
||||
if (id == MS_RTT_4103_RECEIVED_CHAR) {
|
||||
#if 0
|
||||
RealtimeTextReceivedCharacter *data = reinterpret_cast<RealtimeTextReceivedCharacter *>(arg);
|
||||
LinphoneChatRoom * chat_room = linphone_call_get_chat_room(call);
|
||||
linphone_core_real_time_text_received(call->core, chat_room, data->character, call);
|
||||
#endif
|
||||
if (listener)
|
||||
listener->onRealTimeTextCharacterReceived(q->getSharedFromThis(), data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,7 +96,10 @@ Content ContentManager::contentListToMultipart (const list<Content> &contents) {
|
|||
|
||||
Content content;
|
||||
content.setBody(desc);
|
||||
content.setContentType(ContentType::Multipart);
|
||||
ContentType contentType = ContentType::Multipart;
|
||||
string boundary = "boundary=" + string(MULTIPART_BOUNDARY);
|
||||
contentType.setParameter(boundary);
|
||||
content.setContentType(contentType);
|
||||
|
||||
belle_sip_free(desc);
|
||||
belle_sip_object_unref(mpbh);
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ bool AbstractDb::forceReconnect () {
|
|||
try {
|
||||
lInfo() << "Reconnect... Try: " << i;
|
||||
session->reconnect();
|
||||
init();
|
||||
lInfo() << "Database reconnection successful!";
|
||||
return true;
|
||||
} catch (const soci::soci_error &e) {
|
||||
|
|
|
|||
|
|
@ -28,25 +28,21 @@
|
|||
|
||||
// =============================================================================
|
||||
|
||||
namespace soci {
|
||||
class row;
|
||||
}
|
||||
|
||||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
class Content;
|
||||
|
||||
class MainDbPrivate : public AbstractDbPrivate {
|
||||
public:
|
||||
struct Statements;
|
||||
|
||||
mutable std::unordered_map<long long, std::weak_ptr<EventLog>> storageIdToEvent;
|
||||
mutable std::unordered_map<long long, std::weak_ptr<ChatMessage>> storageIdToChatMessage;
|
||||
|
||||
private:
|
||||
// ---------------------------------------------------------------------------
|
||||
// SOCI helpers.
|
||||
// ---------------------------------------------------------------------------
|
||||
std::unique_ptr<Statements> statements;
|
||||
|
||||
long long resolveId (const soci::row &row, int col) const;
|
||||
void initStatements ();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Low level API.
|
||||
|
|
@ -156,6 +152,7 @@ private:
|
|||
|
||||
unsigned int getModuleVersion (const std::string &name);
|
||||
void updateModuleVersion (const std::string &name, unsigned int version);
|
||||
void updateSchema ();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Import.
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
|
||||
#include "linphone/utils/algorithm.h"
|
||||
#include "linphone/utils/utils.h"
|
||||
|
||||
#include "chat/chat-message/chat-message-p.h"
|
||||
|
|
@ -36,11 +36,6 @@
|
|||
#include "main-db-key-p.h"
|
||||
#include "main-db-p.h"
|
||||
|
||||
#define DB_MODULE_VERSION_EVENTS L_VERSION(1, 0, 0)
|
||||
#define DB_MODULE_VERSION_FRIENDS L_VERSION(1, 0, 0)
|
||||
#define DB_MODULE_VERSION_LEGACY_FRIENDS_IMPORT L_VERSION(1, 0, 0)
|
||||
#define DB_MODULE_VERSION_LEGACY_HISTORY_IMPORT L_VERSION(1, 0, 0)
|
||||
|
||||
// =============================================================================
|
||||
|
||||
// See: http://soci.sourceforge.net/doc/3.2/exchange.html
|
||||
|
|
@ -52,6 +47,41 @@ using namespace std;
|
|||
|
||||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
namespace {
|
||||
constexpr unsigned int ModuleVersionEvents = makeVersion(1, 0, 1);
|
||||
constexpr unsigned int ModuleVersionFriends = makeVersion(1, 0, 0);
|
||||
constexpr unsigned int ModuleVersionLegacyFriendsImport = makeVersion(1, 0, 0);
|
||||
constexpr unsigned int ModuleVersionLegacyHistoryImport = makeVersion(1, 0, 0);
|
||||
|
||||
constexpr int LegacyFriendListColId = 0;
|
||||
constexpr int LegacyFriendListColName = 1;
|
||||
constexpr int LegacyFriendListColRlsUri = 2;
|
||||
constexpr int LegacyFriendListColSyncUri = 3;
|
||||
constexpr int LegacyFriendListColRevision = 4;
|
||||
|
||||
constexpr int LegacyFriendColFriendListId = 1;
|
||||
constexpr int LegacyFriendColSipAddress = 2;
|
||||
constexpr int LegacyFriendColSubscribePolicy = 3;
|
||||
constexpr int LegacyFriendColSendSubscribe = 4;
|
||||
constexpr int LegacyFriendColRefKey = 5;
|
||||
constexpr int LegacyFriendColVCard = 6;
|
||||
constexpr int LegacyFriendColVCardEtag = 7;
|
||||
constexpr int LegacyFriendColVCardSyncUri = 8;
|
||||
constexpr int LegacyFriendColPresenceReceived = 9;
|
||||
|
||||
constexpr int LegacyMessageColLocalAddress = 1;
|
||||
constexpr int LegacyMessageColRemoteAddress = 2;
|
||||
constexpr int LegacyMessageColDirection = 3;
|
||||
constexpr int LegacyMessageColText = 4;
|
||||
constexpr int LegacyMessageColState = 7;
|
||||
constexpr int LegacyMessageColUrl = 8;
|
||||
constexpr int LegacyMessageColDate = 9;
|
||||
constexpr int LegacyMessageColAppData = 10;
|
||||
constexpr int LegacyMessageColContentId = 11;
|
||||
constexpr int LegacyMessageColContentType = 13;
|
||||
constexpr int LegacyMessageColIsSecured = 14;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
MainDb::MainDb (const shared_ptr<Core> &core) : AbstractDb(*new MainDbPrivate), CoreAccessor(core) {}
|
||||
|
|
@ -80,20 +110,30 @@ struct SafeTransactionInfo {
|
|||
|
||||
template<typename Function>
|
||||
class SafeTransaction {
|
||||
using InternalReturnType = typename remove_reference<decltype(declval<Function>()())>::type;
|
||||
|
||||
public:
|
||||
using ReturnType = typename remove_reference<decltype(declval<Function>()())>::type;
|
||||
using ReturnType = typename std::conditional<
|
||||
std::is_same<InternalReturnType, void>::value,
|
||||
bool,
|
||||
InternalReturnType
|
||||
>::type;
|
||||
|
||||
SafeTransaction (SafeTransactionInfo &info, Function function) : mFunction(move(function)) {
|
||||
try {
|
||||
mResult = mFunction();
|
||||
mResult= exec<InternalReturnType>();
|
||||
} catch (const soci::soci_error &e) {
|
||||
lWarning() << "Catched exception in MainDb::" << info.name << ".";
|
||||
lWarning() << "Catched exception in MainDb::" << info.name << "(" << e.what() << ").";
|
||||
soci::soci_error::error_category category = e.get_error_category();
|
||||
if (
|
||||
(category == soci::soci_error::connection_error || category == soci::soci_error::unknown) &&
|
||||
info.mainDb->forceReconnect()
|
||||
) {
|
||||
mResult = mFunction();
|
||||
try {
|
||||
mResult = exec<InternalReturnType>();
|
||||
} catch (const exception &e) {
|
||||
lError() << "Unable to execute query after reconnect in MainDb::" << info.name << "(" << e.what() << ").";
|
||||
}
|
||||
return;
|
||||
}
|
||||
lError() << "Unhandled [" << getErrorCategoryAsString(category) << "] exception in MainDb::" <<
|
||||
|
|
@ -110,6 +150,19 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// Exec function with no return type.
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_same<T, void>::value, bool>::type exec () const {
|
||||
mFunction();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Exec function with return type.
|
||||
template<typename T>
|
||||
typename std::enable_if<!std::is_same<T, void>::value, T>::type exec () const {
|
||||
return mFunction();
|
||||
}
|
||||
|
||||
static const char *getErrorCategoryAsString (soci::soci_error::error_category category) {
|
||||
switch (category) {
|
||||
case soci::soci_error::connection_error:
|
||||
|
|
@ -163,10 +216,12 @@ static constexpr const char *mapEnumToSql (const EnumToSql<T> enumToSql[], size_
|
|||
);
|
||||
}
|
||||
|
||||
// Update me event-log-enums values are changed!
|
||||
static constexpr EnumToSql<MainDb::Filter> eventFilterToSql[] = {
|
||||
{ MainDb::ConferenceCallFilter, "3, 4" },
|
||||
{ MainDb::ConferenceChatMessageFilter, "5" },
|
||||
{ MainDb::ConferenceInfoFilter, "1, 2, 6, 7, 8, 9, 10, 11, 12" }
|
||||
{ MainDb::ConferenceInfoFilter, "1, 2, 6, 7, 8, 9, 10, 11, 12" },
|
||||
{ MainDb::ConferenceInfoNoDeviceFilter, "1, 2, 6, 7, 8, 9, 12" }
|
||||
};
|
||||
|
||||
static constexpr const char *mapEventFilterToSql (MainDb::Filter filter) {
|
||||
|
|
@ -182,11 +237,7 @@ static string buildSqlEventFilter (
|
|||
MainDb::FilterMask mask,
|
||||
const string &condKeyWord = "WHERE"
|
||||
) {
|
||||
L_ASSERT(
|
||||
find_if(filters.cbegin(), filters.cend(), [](const MainDb::Filter &filter) {
|
||||
return filter == MainDb::NoFilter;
|
||||
}) == filters.cend()
|
||||
);
|
||||
L_ASSERT(findIf(filters, [](const MainDb::Filter &filter) { return filter == MainDb::NoFilter; }) == filters.cend());
|
||||
|
||||
if (mask == MainDb::NoFilter)
|
||||
return "";
|
||||
|
|
@ -231,15 +282,57 @@ static constexpr string &blobToString (string &in) {
|
|||
return in;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Statements and helpers.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
long long MainDbPrivate::resolveId (const soci::row &row, int col) const {
|
||||
L_Q();
|
||||
// See: http://soci.sourceforge.net/doc/master/backends/
|
||||
// `row id` is not supported by soci on Sqlite3. It's necessary to cast id to int...
|
||||
return q->getBackend() == AbstractDb::Sqlite3
|
||||
? static_cast<long long>(row.get<int>(0))
|
||||
: static_cast<long long>(row.get<unsigned long long>(0));
|
||||
class StatementBind {
|
||||
public:
|
||||
StatementBind (soci::statement &stmt) : mStmt(stmt) {}
|
||||
|
||||
~StatementBind () {
|
||||
mStmt.bind_clean_up();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bind (const T &var, const char *name) {
|
||||
mStmt.exchange(soci::use(var, name));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void bindResult (T &var) {
|
||||
mStmt.exchange(soci::into(var));
|
||||
}
|
||||
|
||||
bool exec () {
|
||||
mStmt.define_and_bind();
|
||||
return mStmt.execute(true);
|
||||
}
|
||||
|
||||
private:
|
||||
soci::statement &mStmt;
|
||||
};
|
||||
|
||||
static inline unique_ptr<soci::statement> makeStatement (soci::session &session, const char *stmt) {
|
||||
return makeUnique<soci::statement>(session.prepare << stmt);
|
||||
}
|
||||
|
||||
struct MainDbPrivate::Statements {
|
||||
typedef unique_ptr<soci::statement> Statement;
|
||||
|
||||
Statement selectSipAddressId;
|
||||
Statement selectChatRoomId;
|
||||
};
|
||||
|
||||
void MainDbPrivate::initStatements () {
|
||||
soci::session *session = dbSession.getBackendSession();
|
||||
statements = makeUnique<Statements>();
|
||||
|
||||
statements->selectSipAddressId = makeStatement(*session, "SELECT id FROM sip_address WHERE value = :sipAddress");
|
||||
statements->selectChatRoomId = makeStatement(
|
||||
*session,
|
||||
"SELECT id FROM chat_room WHERE peer_sip_address_id = :peerSipAddressId AND local_sip_address_id = :localSipAddressId"
|
||||
);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -424,39 +517,35 @@ void MainDbPrivate::insertChatRoomParticipantDevice (
|
|||
}
|
||||
|
||||
void MainDbPrivate::insertChatMessageParticipant (long long eventId, long long sipAddressId, int state) {
|
||||
// TODO: Deal with read messages.
|
||||
// Remove if displayed? Think a good alorithm for mark as read.
|
||||
soci::session *session = dbSession.getBackendSession();
|
||||
soci::statement statement = (
|
||||
session->prepare << "UPDATE chat_message_participant SET state = :state"
|
||||
" WHERE event_id = :eventId AND participant_sip_address_id = :sipAddressId",
|
||||
soci::use(state), soci::use(eventId), soci::use(sipAddressId)
|
||||
);
|
||||
statement.execute();
|
||||
if (statement.get_affected_rows() == 0 && state != static_cast<int>(ChatMessage::State::Displayed))
|
||||
if (state != static_cast<int>(ChatMessage::State::Displayed)) {
|
||||
soci::session *session = dbSession.getBackendSession();
|
||||
*session << "INSERT INTO chat_message_participant (event_id, participant_sip_address_id, state)"
|
||||
" VALUES (:eventId, :sipAddressId, :state)",
|
||||
soci::use(eventId), soci::use(sipAddressId), soci::use(state);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
long long MainDbPrivate::selectSipAddressId (const string &sipAddress) const {
|
||||
soci::session *session = dbSession.getBackendSession();
|
||||
|
||||
long long id;
|
||||
*session << "SELECT id FROM sip_address WHERE value = :sipAddress", soci::use(sipAddress), soci::into(id);
|
||||
return session->got_data() ? id : -1;
|
||||
|
||||
StatementBind stmt(*statements->selectSipAddressId);
|
||||
stmt.bind(sipAddress, "sipAddress");
|
||||
stmt.bindResult(id);
|
||||
|
||||
return stmt.exec() ? id : -1;
|
||||
}
|
||||
|
||||
long long MainDbPrivate::selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const {
|
||||
soci::session *session = dbSession.getBackendSession();
|
||||
|
||||
long long id;
|
||||
*session << "SELECT id FROM chat_room"
|
||||
" WHERE peer_sip_address_id = :peerSipAddressId AND local_sip_address_id = :localSipAddressId",
|
||||
soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::into(id);
|
||||
return session->got_data() ? id : -1;
|
||||
|
||||
StatementBind stmt(*statements->selectChatRoomId);
|
||||
stmt.bind(peerSipAddressId, "peerSipAddressId");
|
||||
stmt.bind(localSipAddressId, "localSipAddressId");
|
||||
stmt.bindResult(id);
|
||||
|
||||
return stmt.exec() ? id : -1;
|
||||
}
|
||||
|
||||
long long MainDbPrivate::selectChatRoomId (const ChatRoomId &chatRoomId) const {
|
||||
|
|
@ -650,12 +739,12 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceChatMessageEvent (
|
|||
|
||||
chatMessage = shared_ptr<ChatMessage>(new ChatMessage(
|
||||
chatRoom,
|
||||
static_cast<ChatMessage::Direction>(direction)
|
||||
ChatMessage::Direction(direction)
|
||||
));
|
||||
chatMessage->setIsSecured(static_cast<bool>(isSecured));
|
||||
chatMessage->setIsSecured(bool(isSecured));
|
||||
|
||||
ChatMessagePrivate *dChatMessage = chatMessage->getPrivate();
|
||||
dChatMessage->setState(static_cast<ChatMessage::State>(state), true);
|
||||
dChatMessage->setState(ChatMessage::State(state), true);
|
||||
|
||||
dChatMessage->forceFromAddress(IdentityAddress(fromSipAddress));
|
||||
dChatMessage->forceToAddress(IdentityAddress(toSipAddress));
|
||||
|
|
@ -673,7 +762,7 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceChatMessageEvent (
|
|||
soci::rowset<soci::row> rows = (session->prepare << query, soci::use(eventId));
|
||||
for (const auto &row : rows) {
|
||||
ContentType contentType(row.get<string>(2));
|
||||
const long long &contentId = resolveId(row, 0);
|
||||
const long long &contentId = dbSession.resolveId(row, 0);
|
||||
Content *content;
|
||||
|
||||
if (contentType == ContentType::FileTransfer) {
|
||||
|
|
@ -692,7 +781,7 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceChatMessageEvent (
|
|||
|
||||
FileContent *fileContent = new FileContent();
|
||||
fileContent->setFileName(name);
|
||||
fileContent->setFileSize(static_cast<size_t>(size));
|
||||
fileContent->setFileSize(size_t(size));
|
||||
fileContent->setFilePath(path);
|
||||
|
||||
content = fileContent;
|
||||
|
|
@ -703,6 +792,7 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceChatMessageEvent (
|
|||
content->setBody(row.get<string>(3));
|
||||
|
||||
// 2.2 - Fetch contents' app data.
|
||||
// TODO: Do not test backend, encapsulate!!!
|
||||
if (q->getBackend() == MainDb::Backend::Sqlite3) {
|
||||
soci::blob data(*session);
|
||||
fetchContentAppData(session, *content, contentId, data);
|
||||
|
|
@ -813,7 +903,7 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceSubjectEvent (
|
|||
long long MainDbPrivate::insertEvent (const shared_ptr<EventLog> &eventLog) {
|
||||
soci::session *session = dbSession.getBackendSession();
|
||||
|
||||
const int &type = static_cast<int>(eventLog->getType());
|
||||
const int &type = int(eventLog->getType());
|
||||
const tm &creationTime = Utils::getTimeTAsTm(eventLog->getCreationTime());
|
||||
*session << "INSERT INTO event (type, creation_time) VALUES (:type, :creationTime)",
|
||||
soci::use(type),
|
||||
|
|
@ -878,8 +968,8 @@ long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptr<Even
|
|||
const long long &fromSipAddressId = insertSipAddress(chatMessage->getFromAddress().asString());
|
||||
const long long &toSipAddressId = insertSipAddress(chatMessage->getToAddress().asString());
|
||||
const tm &messageTime = Utils::getTimeTAsTm(chatMessage->getTime());
|
||||
const int &state = static_cast<int>(chatMessage->getState());
|
||||
const int &direction = static_cast<int>(chatMessage->getDirection());
|
||||
const int &state = int(chatMessage->getState());
|
||||
const int &direction = int(chatMessage->getDirection());
|
||||
const string &imdnMessageId = chatMessage->getImdnMessageId();
|
||||
const int &isSecured = chatMessage->isSecured() ? 1 : 0;
|
||||
|
||||
|
|
@ -896,6 +986,11 @@ long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptr<Even
|
|||
for (const Content *content : chatMessage->getContents())
|
||||
insertContent(eventId, *content);
|
||||
|
||||
for (const auto &participant : chatRoom->getParticipants()) {
|
||||
const long long &participantSipAddressId = selectSipAddressId(participant->getAddress().asString());
|
||||
insertChatMessageParticipant(eventId, participantSipAddressId, state);
|
||||
}
|
||||
|
||||
return eventId;
|
||||
}
|
||||
|
||||
|
|
@ -912,7 +1007,7 @@ void MainDbPrivate::updateConferenceChatMessageEvent (const shared_ptr<EventLog>
|
|||
const long long &eventId = dEventKey->storageId;
|
||||
|
||||
soci::session *session = dbSession.getBackendSession();
|
||||
const int &state = static_cast<int>(chatMessage->getState());
|
||||
const int &state = int(chatMessage->getState());
|
||||
const string &imdnMessageId = chatMessage->getImdnMessageId();
|
||||
*session << "UPDATE conference_chat_message_event SET state = :state, imdn_message_id = :imdnMessageId"
|
||||
" WHERE event_id = :eventId",
|
||||
|
|
@ -1096,7 +1191,7 @@ void MainDbPrivate::invalidConferenceEventsFromQuery (const string &query, long
|
|||
soci::session *session = dbSession.getBackendSession();
|
||||
soci::rowset<soci::row> rows = (session->prepare << query, soci::use(chatRoomId));
|
||||
for (const auto &row : rows) {
|
||||
long long eventId = resolveId(row, 0);
|
||||
long long eventId = dbSession.resolveId(row, 0);
|
||||
shared_ptr<EventLog> eventLog = getEventFromCache(eventId);
|
||||
if (eventLog) {
|
||||
const EventLogPrivate *dEventLog = eventLog->getPrivate();
|
||||
|
|
@ -1133,60 +1228,51 @@ void MainDbPrivate::updateModuleVersion (const string &name, unsigned int versio
|
|||
soci::use(name), soci::use(version);
|
||||
}
|
||||
|
||||
void MainDbPrivate::updateSchema () {
|
||||
soci::session *session = dbSession.getBackendSession();
|
||||
unsigned int version = getModuleVersion("events");
|
||||
|
||||
if (version < makeVersion(1, 0, 1)) {
|
||||
*session << "ALTER TABLE chat_room_participant_device ADD COLUMN state TINYINT UNSIGNED DEFAULT 0";
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define CHECK_LEGACY_TABLE_EXISTS(SESSION, NAME) \
|
||||
do { \
|
||||
SESSION << "SELECT name FROM sqlite_master WHERE type='table' AND name='" NAME "'"; \
|
||||
return SESSION.got_data() > 0; \
|
||||
} while (false);
|
||||
// NOTE: Legacy supports only sqlite.
|
||||
static inline bool checkLegacyTableExists (soci::session &session, const string &name) {
|
||||
session << "SELECT name FROM sqlite_master WHERE type='table' AND name = :name", soci::use(name);
|
||||
return session.got_data() > 0;
|
||||
}
|
||||
|
||||
static inline bool checkLegacyFriendsTableExists (soci::session &session) {
|
||||
CHECK_LEGACY_TABLE_EXISTS(session, "friends");
|
||||
return checkLegacyTableExists(session, "friends");
|
||||
}
|
||||
|
||||
static inline bool checkLegacyHistoryTableExists (soci::session &session) {
|
||||
CHECK_LEGACY_TABLE_EXISTS(session, "history");
|
||||
return checkLegacyTableExists(session, "history");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T getValueFromRow (const soci::row &row, int index, bool &isNull) {
|
||||
isNull = false;
|
||||
|
||||
try {
|
||||
return row.get<T>(static_cast<size_t>(index));
|
||||
} catch (const exception &) {
|
||||
if (row.get_indicator(size_t(index)) == soci::i_null){
|
||||
isNull = true;
|
||||
return T();
|
||||
}
|
||||
|
||||
return T();
|
||||
return row.get<T>(size_t(index));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#define LEGACY_FRIEND_LIST_COL_ID 0
|
||||
#define LEGACY_FRIEND_LIST_COL_NAME 1
|
||||
#define LEGACY_FRIEND_LIST_COL_RLS_URI 2
|
||||
#define LEGACY_FRIEND_LIST_COL_SYNC_URI 3
|
||||
#define LEGACY_FRIEND_LIST_COL_REVISION 4
|
||||
|
||||
#define LEGACY_FRIEND_COL_FRIEND_LIST_ID 1
|
||||
#define LEGACY_FRIEND_COL_SIP_ADDRESS 2
|
||||
#define LEGACY_FRIEND_COL_SUBSCRIBE_POLICY 3
|
||||
#define LEGACY_FRIEND_COL_SEND_SUBSCRIBE 4
|
||||
#define LEGACY_FRIEND_COL_REF_KEY 5
|
||||
#define LEGACY_FRIEND_COL_V_CARD 6
|
||||
#define LEGACY_FRIEND_COL_V_CARD_ETAG 7
|
||||
#define LEGACY_FRIEND_COL_V_CARD_SYNC_URI 8
|
||||
#define LEGACY_FRIEND_COL_PRESENCE_RECEIVED 9
|
||||
|
||||
void MainDbPrivate::importLegacyFriends (DbSession &inDbSession) {
|
||||
soci::session *inSession = inDbSession.getBackendSession();
|
||||
soci::transaction tr(*dbSession.getBackendSession());
|
||||
|
||||
if (getModuleVersion("legacy-friends-import") >= L_VERSION(1, 0, 0))
|
||||
if (getModuleVersion("legacy-friends-import") >= makeVersion(1, 0, 0))
|
||||
return;
|
||||
updateModuleVersion("legacy-friends-import", DB_MODULE_VERSION_LEGACY_FRIENDS_IMPORT);
|
||||
updateModuleVersion("legacy-friends-import", ModuleVersionLegacyFriendsImport);
|
||||
|
||||
if (!checkLegacyFriendsTableExists(*inSession))
|
||||
return;
|
||||
|
|
@ -1198,10 +1284,10 @@ void MainDbPrivate::importLegacyFriends (DbSession &inDbSession) {
|
|||
try {
|
||||
set<string> names;
|
||||
for (const auto &friendList : friendsLists) {
|
||||
const string &name = friendList.get<string>(LEGACY_FRIEND_LIST_COL_NAME, "");
|
||||
const string &rlsUri = friendList.get<string>(LEGACY_FRIEND_LIST_COL_RLS_URI, "");
|
||||
const string &syncUri = friendList.get<string>(LEGACY_FRIEND_LIST_COL_SYNC_URI, "");
|
||||
const int &revision = friendList.get<int>(LEGACY_FRIEND_LIST_COL_REVISION, 0);
|
||||
const string &name = friendList.get<string>(LegacyFriendListColName, "");
|
||||
const string &rlsUri = friendList.get<string>(LegacyFriendListColRlsUri, "");
|
||||
const string &syncUri = friendList.get<string>(LegacyFriendListColSyncUri, "");
|
||||
const int &revision = friendList.get<int>(LegacyFriendListColRevision, 0);
|
||||
|
||||
string uniqueName = name;
|
||||
for (int id = 0; names.find(uniqueName) != names.end(); uniqueName = name + "-" + Utils::toString(id++));
|
||||
|
|
@ -1210,7 +1296,7 @@ void MainDbPrivate::importLegacyFriends (DbSession &inDbSession) {
|
|||
*session << "INSERT INTO friends_list (name, rls_uri, sync_uri, revision) VALUES ("
|
||||
" :name, :rlsUri, :syncUri, :revision"
|
||||
")", soci::use(uniqueName), soci::use(rlsUri), soci::use(syncUri), soci::use(revision);
|
||||
resolvedListsIds[friendList.get<int>(LEGACY_FRIEND_LIST_COL_ID)] = dbSession.getLastInsertId();
|
||||
resolvedListsIds[friendList.get<int>(LegacyFriendListColId)] = dbSession.getLastInsertId();
|
||||
}
|
||||
} catch (const exception &e) {
|
||||
lWarning() << "Failed to import legacy friends list: " << e.what() << ".";
|
||||
|
|
@ -1222,19 +1308,19 @@ void MainDbPrivate::importLegacyFriends (DbSession &inDbSession) {
|
|||
for (const auto &friendInfo : friends) {
|
||||
long long friendsListId;
|
||||
{
|
||||
auto it = resolvedListsIds.find(friendInfo.get<int>(LEGACY_FRIEND_COL_FRIEND_LIST_ID, -1));
|
||||
auto it = resolvedListsIds.find(friendInfo.get<int>(LegacyFriendColFriendListId, -1));
|
||||
if (it == resolvedListsIds.end())
|
||||
continue;
|
||||
friendsListId = it->second;
|
||||
}
|
||||
|
||||
const long long &sipAddressId = insertSipAddress(friendInfo.get<string>(LEGACY_FRIEND_COL_SIP_ADDRESS, ""));
|
||||
const int &subscribePolicy = friendInfo.get<int>(LEGACY_FRIEND_COL_SUBSCRIBE_POLICY, LinphoneSPAccept);
|
||||
const int &sendSubscribe = friendInfo.get<int>(LEGACY_FRIEND_COL_SEND_SUBSCRIBE, 1);
|
||||
const string &vCard = friendInfo.get<string>(LEGACY_FRIEND_COL_V_CARD, "");
|
||||
const string &vCardEtag = friendInfo.get<string>(LEGACY_FRIEND_COL_V_CARD_ETAG, "");
|
||||
const string &vCardSyncUri = friendInfo.get<string>(LEGACY_FRIEND_COL_V_CARD_SYNC_URI, "");
|
||||
const int &presenceReveived = friendInfo.get<int>(LEGACY_FRIEND_COL_PRESENCE_RECEIVED, 0);
|
||||
const long long &sipAddressId = insertSipAddress(friendInfo.get<string>(LegacyFriendColSipAddress, ""));
|
||||
const int &subscribePolicy = friendInfo.get<int>(LegacyFriendColSubscribePolicy, LinphoneSPAccept);
|
||||
const int &sendSubscribe = friendInfo.get<int>(LegacyFriendColSendSubscribe, 1);
|
||||
const string &vCard = friendInfo.get<string>(LegacyFriendColVCard, "");
|
||||
const string &vCardEtag = friendInfo.get<string>(LegacyFriendColVCardEtag, "");
|
||||
const string &vCardSyncUri = friendInfo.get<string>(LegacyFriendColVCardSyncUri, "");
|
||||
const int &presenceReveived = friendInfo.get<int>(LegacyFriendColPresenceReceived, 0);
|
||||
|
||||
*session << "INSERT INTO friend ("
|
||||
" sip_address_id, friends_list_id, subscribe_policy, send_subscribe,"
|
||||
|
|
@ -1246,7 +1332,7 @@ void MainDbPrivate::importLegacyFriends (DbSession &inDbSession) {
|
|||
soci::use(presenceReveived), soci::use(vCard), soci::use(vCardEtag), soci::use(vCardSyncUri);
|
||||
|
||||
bool isNull;
|
||||
const string &data = getValueFromRow<string>(friendInfo, LEGACY_FRIEND_COL_REF_KEY, isNull);
|
||||
const string &data = getValueFromRow<string>(friendInfo, LegacyFriendColRefKey, isNull);
|
||||
if (!isNull)
|
||||
*session << "INSERT INTO friend_app_data (friend_id, name, data) VALUES"
|
||||
" (:friendId, 'legacy', :data)",
|
||||
|
|
@ -1261,27 +1347,14 @@ void MainDbPrivate::importLegacyFriends (DbSession &inDbSession) {
|
|||
lInfo() << "Successful import of legacy friends.";
|
||||
}
|
||||
|
||||
#define LEGACY_MESSAGE_COL_LOCAL_ADDRESS 1
|
||||
#define LEGACY_MESSAGE_COL_REMOTE_ADDRESS 2
|
||||
#define LEGACY_MESSAGE_COL_DIRECTION 3
|
||||
#define LEGACY_MESSAGE_COL_TEXT 4
|
||||
#define LEGACY_MESSAGE_COL_STATE 7
|
||||
#define LEGACY_MESSAGE_COL_URL 8
|
||||
#define LEGACY_MESSAGE_COL_DATE 9
|
||||
#define LEGACY_MESSAGE_COL_APP_DATA 10
|
||||
#define LEGACY_MESSAGE_COL_CONTENT_ID 11
|
||||
#define LEGACY_MESSAGE_COL_IMDN_MESSAGE_ID 12
|
||||
#define LEGACY_MESSAGE_COL_CONTENT_TYPE 13
|
||||
#define LEGACY_MESSAGE_COL_IS_SECURED 14
|
||||
|
||||
void MainDbPrivate::importLegacyHistory (DbSession &inDbSession) {
|
||||
soci::session *inSession = inDbSession.getBackendSession();
|
||||
soci::transaction tr(*dbSession.getBackendSession());
|
||||
|
||||
unsigned int version = getModuleVersion("legacy-history-import");
|
||||
if (version >= L_VERSION(1, 0, 0))
|
||||
if (version >= makeVersion(1, 0, 0))
|
||||
return;
|
||||
updateModuleVersion("legacy-history-import", DB_MODULE_VERSION_LEGACY_HISTORY_IMPORT);
|
||||
updateModuleVersion("legacy-history-import", ModuleVersionLegacyHistoryImport);
|
||||
|
||||
if (!checkLegacyHistoryTableExists(*inSession))
|
||||
return;
|
||||
|
|
@ -1289,27 +1362,27 @@ void MainDbPrivate::importLegacyHistory (DbSession &inDbSession) {
|
|||
soci::rowset<soci::row> messages = (inSession->prepare << "SELECT * FROM history");
|
||||
try {
|
||||
for (const auto &message : messages) {
|
||||
const int direction = message.get<int>(LEGACY_MESSAGE_COL_DIRECTION);
|
||||
const int direction = message.get<int>(LegacyMessageColDirection);
|
||||
if (direction != 0 && direction != 1) {
|
||||
lWarning() << "Unable to import legacy message with invalid direction.";
|
||||
continue;
|
||||
}
|
||||
|
||||
const int &state = message.get<int>(
|
||||
LEGACY_MESSAGE_COL_STATE, static_cast<int>(ChatMessage::State::Displayed)
|
||||
LegacyMessageColState, int(ChatMessage::State::Displayed)
|
||||
);
|
||||
if (state < 0 || state > static_cast<int>(ChatMessage::State::Displayed)) {
|
||||
if (state < 0 || state > int(ChatMessage::State::Displayed)) {
|
||||
lWarning() << "Unable to import legacy message with invalid state.";
|
||||
continue;
|
||||
}
|
||||
|
||||
const tm &creationTime = Utils::getTimeTAsTm(message.get<int>(LEGACY_MESSAGE_COL_DATE, 0));
|
||||
const tm &creationTime = Utils::getTimeTAsTm(message.get<int>(LegacyMessageColDate, 0));
|
||||
|
||||
bool isNull;
|
||||
getValueFromRow<string>(message, LEGACY_MESSAGE_COL_URL, isNull);
|
||||
getValueFromRow<string>(message, LegacyMessageColUrl, isNull);
|
||||
|
||||
const int &contentId = message.get<int>(LEGACY_MESSAGE_COL_CONTENT_ID, -1);
|
||||
ContentType contentType(message.get<string>(LEGACY_MESSAGE_COL_CONTENT_TYPE, ""));
|
||||
const int &contentId = message.get<int>(LegacyMessageColContentId, -1);
|
||||
ContentType contentType(message.get<string>(LegacyMessageColContentType, ""));
|
||||
if (!contentType.isValid())
|
||||
contentType = contentId != -1
|
||||
? ContentType::FileTransfer
|
||||
|
|
@ -1319,7 +1392,7 @@ void MainDbPrivate::importLegacyHistory (DbSession &inDbSession) {
|
|||
continue;
|
||||
}
|
||||
|
||||
const string &text = getValueFromRow<string>(message, LEGACY_MESSAGE_COL_TEXT, isNull);
|
||||
const string &text = getValueFromRow<string>(message, LegacyMessageColText, isNull);
|
||||
|
||||
Content content;
|
||||
content.setContentType(contentType);
|
||||
|
|
@ -1335,7 +1408,7 @@ void MainDbPrivate::importLegacyHistory (DbSession &inDbSession) {
|
|||
continue;
|
||||
}
|
||||
|
||||
const string appData = getValueFromRow<string>(message, LEGACY_MESSAGE_COL_APP_DATA, isNull);
|
||||
const string appData = getValueFromRow<string>(message, LegacyMessageColAppData, isNull);
|
||||
if (isNull) {
|
||||
lWarning() << "Unable to import legacy file message without app data.";
|
||||
continue;
|
||||
|
|
@ -1345,19 +1418,19 @@ void MainDbPrivate::importLegacyHistory (DbSession &inDbSession) {
|
|||
}
|
||||
|
||||
soci::session *session = dbSession.getBackendSession();
|
||||
const int &eventType = static_cast<int>(EventLog::Type::ConferenceChatMessage);
|
||||
const int &eventType = int(EventLog::Type::ConferenceChatMessage);
|
||||
*session << "INSERT INTO event (type, creation_time) VALUES (:type, :creationTime)",
|
||||
soci::use(eventType), soci::use(creationTime);
|
||||
|
||||
const long long &eventId = dbSession.getLastInsertId();
|
||||
const long long &localSipAddressId = insertSipAddress(message.get<string>(LEGACY_MESSAGE_COL_LOCAL_ADDRESS));
|
||||
const long long &remoteSipAddressId = insertSipAddress(message.get<string>(LEGACY_MESSAGE_COL_REMOTE_ADDRESS));
|
||||
const long long &localSipAddressId = insertSipAddress(message.get<string>(LegacyMessageColLocalAddress));
|
||||
const long long &remoteSipAddressId = insertSipAddress(message.get<string>(LegacyMessageColRemoteAddress));
|
||||
const long long &chatRoomId = insertOrUpdateImportedBasicChatRoom(
|
||||
remoteSipAddressId,
|
||||
localSipAddressId,
|
||||
creationTime
|
||||
);
|
||||
const int &isSecured = message.get<int>(LEGACY_MESSAGE_COL_IS_SECURED, 0);
|
||||
const int &isSecured = message.get<int>(LegacyMessageColIsSecured, 0);
|
||||
|
||||
*session << "INSERT INTO conference_event (event_id, chat_room_id)"
|
||||
" VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId);
|
||||
|
|
@ -1375,7 +1448,7 @@ void MainDbPrivate::importLegacyHistory (DbSession &inDbSession) {
|
|||
insertContent(eventId, content);
|
||||
insertChatRoomParticipant(chatRoomId, remoteSipAddressId, false);
|
||||
|
||||
if (state != static_cast<int>(ChatMessage::State::Displayed))
|
||||
if (state != int(ChatMessage::State::Displayed))
|
||||
insertChatMessageParticipant(eventId, remoteSipAddressId, state);
|
||||
}
|
||||
|
||||
|
|
@ -1674,32 +1747,6 @@ void MainDb::init () {
|
|||
" ON DELETE CASCADE"
|
||||
") " + charset;
|
||||
|
||||
// Trigger to delete participant_message cache entries.
|
||||
// TODO: Fix me in the future. (Problem on Mysql backend.)
|
||||
#if 0
|
||||
string displayedId = Utils::toString(static_cast<int>(ChatMessage::State::Displayed));
|
||||
string participantMessageDeleter =
|
||||
"CREATE TRIGGER IF NOT EXISTS chat_message_participant_deleter"
|
||||
" AFTER UPDATE OF state ON chat_message_participant FOR EACH ROW"
|
||||
" WHEN NEW.state = ";
|
||||
participantMessageDeleter += displayedId;
|
||||
participantMessageDeleter += " AND (SELECT COUNT(*) FROM ("
|
||||
" SELECT state FROM chat_message_participant WHERE"
|
||||
" NEW.event_id = chat_message_participant.event_id"
|
||||
" AND state <> ";
|
||||
participantMessageDeleter += displayedId;
|
||||
participantMessageDeleter += " LIMIT 1"
|
||||
" )) = 0"
|
||||
" BEGIN"
|
||||
" DELETE FROM chat_message_participant WHERE NEW.event_id = chat_message_participant.event_id;"
|
||||
" UPDATE conference_chat_message_event SET state = ";
|
||||
participantMessageDeleter += displayedId;
|
||||
participantMessageDeleter += " WHERE event_id = NEW.event_id;"
|
||||
" END";
|
||||
|
||||
*session << participantMessageDeleter;
|
||||
#endif
|
||||
|
||||
*session <<
|
||||
"CREATE TABLE IF NOT EXISTS friends_list ("
|
||||
" id" + primaryKeyStr("INT UNSIGNED") + ","
|
||||
|
|
@ -1752,8 +1799,30 @@ void MainDb::init () {
|
|||
" version INT UNSIGNED NOT NULL"
|
||||
") " + charset;
|
||||
|
||||
d->updateModuleVersion("events", DB_MODULE_VERSION_EVENTS);
|
||||
d->updateModuleVersion("friends", DB_MODULE_VERSION_FRIENDS);
|
||||
if (getBackend() == Backend::Mysql)
|
||||
*session <<
|
||||
"CREATE TRIGGER IF NOT EXISTS chat_message_participant_deleter"
|
||||
" AFTER UPDATE ON conference_chat_message_event FOR EACH ROW"
|
||||
" BEGIN"
|
||||
" IF NEW.state = " + Utils::toString(int(ChatMessage::State::Displayed)) + " THEN"
|
||||
" DELETE FROM chat_message_participant WHERE event_id = NEW.event_id;"
|
||||
" END IF;"
|
||||
" END ";
|
||||
else
|
||||
*session <<
|
||||
"CREATE TRIGGER IF NOT EXISTS chat_message_participant_deleter"
|
||||
" AFTER UPDATE OF state ON conference_chat_message_event FOR EACH ROW"
|
||||
" WHEN NEW.state = " + Utils::toString(int(ChatMessage::State::Displayed)) +
|
||||
" BEGIN"
|
||||
" DELETE FROM chat_message_participant WHERE event_id = NEW.event_id;"
|
||||
" END ";
|
||||
|
||||
d->updateSchema();
|
||||
|
||||
d->updateModuleVersion("events", ModuleVersionEvents);
|
||||
d->updateModuleVersion("friends", ModuleVersionFriends);
|
||||
|
||||
d->initStatements();
|
||||
}
|
||||
|
||||
bool MainDb::addEvent (const shared_ptr<EventLog> &eventLog) {
|
||||
|
|
@ -1890,7 +1959,7 @@ bool MainDb::deleteEvent (const shared_ptr<const EventLog> &eventLog) {
|
|||
|
||||
int MainDb::getEventCount (FilterMask mask) const {
|
||||
string query = "SELECT COUNT(*) FROM event" +
|
||||
buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter }, mask);
|
||||
buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter, ConferenceInfoNoDeviceFilter }, mask);
|
||||
|
||||
DurationLogger durationLogger(
|
||||
"Get events count with mask=" + Utils::toString(mask) + "."
|
||||
|
|
@ -1944,7 +2013,7 @@ shared_ptr<EventLog> MainDb::getEventFromKey (const MainDbKey &dbKey) {
|
|||
|
||||
return d->selectGenericConferenceEvent(
|
||||
storageId,
|
||||
static_cast<EventLog::Type>(type),
|
||||
EventLog::Type(type),
|
||||
Utils::getTmAsTimeT(creationTime),
|
||||
ChatRoomId(IdentityAddress(peerSipAddress), IdentityAddress(localSipAddress))
|
||||
);
|
||||
|
|
@ -1979,12 +2048,12 @@ list<shared_ptr<EventLog>> MainDb::getConferenceNotifiedEvents (
|
|||
list<shared_ptr<EventLog>> events;
|
||||
soci::rowset<soci::row> rows = (session->prepare << query, soci::use(dbChatRoomId), soci::use(lastNotifyId));
|
||||
for (const auto &row : rows) {
|
||||
long long eventId = d->resolveId(row, 0);
|
||||
long long eventId = d->dbSession.resolveId(row, 0);
|
||||
shared_ptr<EventLog> eventLog = d->getEventFromCache(eventId);
|
||||
|
||||
events.push_back(eventLog ? eventLog : d->selectGenericConferenceEvent(
|
||||
eventId,
|
||||
static_cast<EventLog::Type>(row.get<int>(1)),
|
||||
EventLog::Type(row.get<int>(1)),
|
||||
Utils::getTmAsTimeT(row.get<tm>(2)),
|
||||
chatRoomId
|
||||
));
|
||||
|
|
@ -2031,8 +2100,8 @@ int MainDb::getUnreadChatMessageCount (const ChatRoomId &chatRoomId) const {
|
|||
" SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId"
|
||||
") AND";
|
||||
|
||||
query += " direction = " + Utils::toString(static_cast<int>(ChatMessage::Direction::Incoming)) +
|
||||
+ " AND state <> " + Utils::toString(static_cast<int>(ChatMessage::State::Displayed));
|
||||
query += " direction = " + Utils::toString(int(ChatMessage::Direction::Incoming)) +
|
||||
+ " AND state <> " + Utils::toString(int(ChatMessage::State::Displayed));
|
||||
|
||||
DurationLogger durationLogger(
|
||||
"Get unread chat messages count of: (peer=" + chatRoomId.getPeerAddress().asString() +
|
||||
|
|
@ -2063,13 +2132,13 @@ void MainDb::markChatMessagesAsRead (const ChatRoomId &chatRoomId) const {
|
|||
return;
|
||||
|
||||
string query = "UPDATE conference_chat_message_event"
|
||||
" SET state = " + Utils::toString(static_cast<int>(ChatMessage::State::Displayed)) + " ";
|
||||
" SET state = " + Utils::toString(int(ChatMessage::State::Displayed)) + " ";
|
||||
query += "WHERE";
|
||||
if (chatRoomId.isValid())
|
||||
query += " event_id IN ("
|
||||
" SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId"
|
||||
") AND";
|
||||
query += " direction = " + Utils::toString(static_cast<int>(ChatMessage::Direction::Incoming));
|
||||
query += " direction = " + Utils::toString(int(ChatMessage::Direction::Incoming));
|
||||
|
||||
DurationLogger durationLogger(
|
||||
"Mark chat messages as read of: (peer=" + chatRoomId.getPeerAddress().asString() +
|
||||
|
|
@ -2089,8 +2158,6 @@ void MainDb::markChatMessagesAsRead (const ChatRoomId &chatRoomId) const {
|
|||
*session << query, soci::use(dbChatRoomId);
|
||||
tr.commit();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -2102,8 +2169,8 @@ list<shared_ptr<ChatMessage>> MainDb::getUnreadChatMessages (const ChatRoomId &c
|
|||
if (chatRoomId.isValid())
|
||||
query += " chat_room_id = :chatRoomId AND ";
|
||||
query += " conference_event.event_id = conference_chat_message_event.event_id"
|
||||
" AND direction = " + Utils::toString(static_cast<int>(ChatMessage::Direction::Incoming)) +
|
||||
" AND state <> " + Utils::toString(static_cast<int>(ChatMessage::State::Displayed)) +
|
||||
" AND direction = " + Utils::toString(int(ChatMessage::Direction::Incoming)) +
|
||||
" AND state <> " + Utils::toString(int(ChatMessage::State::Displayed)) +
|
||||
")";
|
||||
|
||||
DurationLogger durationLogger(
|
||||
|
|
@ -2127,7 +2194,7 @@ list<shared_ptr<ChatMessage>> MainDb::getUnreadChatMessages (const ChatRoomId &c
|
|||
: (session->prepare << query);
|
||||
|
||||
for (const auto &row : rows) {
|
||||
long long eventId = d->resolveId(row, 0);
|
||||
long long eventId = d->dbSession.resolveId(row, 0);
|
||||
shared_ptr<EventLog> event = d->getEventFromCache(eventId);
|
||||
|
||||
if (!event)
|
||||
|
|
@ -2146,6 +2213,75 @@ list<shared_ptr<ChatMessage>> MainDb::getUnreadChatMessages (const ChatRoomId &c
|
|||
};
|
||||
}
|
||||
|
||||
list<ChatMessage::State> MainDb::getChatMessageParticipantStates (const shared_ptr<EventLog> &eventLog) const {
|
||||
return L_SAFE_TRANSACTION {
|
||||
L_D();
|
||||
|
||||
soci::session *session = d->dbSession.getBackendSession();
|
||||
|
||||
const EventLogPrivate *dEventLog = eventLog->getPrivate();
|
||||
MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
|
||||
const long long &eventId = dEventKey->storageId;
|
||||
list<ChatMessage::State> states;
|
||||
unsigned int state;
|
||||
|
||||
soci::statement statement = (session->prepare
|
||||
<< "SELECT state FROM chat_message_participant WHERE event_id = :eventId",
|
||||
soci::into(state), soci::use(eventId)
|
||||
);
|
||||
statement.execute();
|
||||
while (statement.fetch())
|
||||
states.push_back(static_cast<ChatMessage::State>(state));
|
||||
|
||||
return states;
|
||||
};
|
||||
}
|
||||
|
||||
ChatMessage::State MainDb::getChatMessageParticipantState (
|
||||
const shared_ptr<EventLog> &eventLog,
|
||||
const IdentityAddress &participantAddress
|
||||
) const {
|
||||
return L_SAFE_TRANSACTION {
|
||||
L_D();
|
||||
|
||||
soci::session *session = d->dbSession.getBackendSession();
|
||||
|
||||
const EventLogPrivate *dEventLog = eventLog->getPrivate();
|
||||
MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
|
||||
const long long &eventId = dEventKey->storageId;
|
||||
const long long &participantSipAddressId = d->selectSipAddressId(participantAddress.asString());
|
||||
unsigned int state;
|
||||
|
||||
*session << "SELECT state FROM chat_message_participant"
|
||||
" WHERE event_id = :eventId AND participant_sip_address_id = :participantSipAddressId",
|
||||
soci::into(state), soci::use(eventId), soci::use(participantSipAddressId);
|
||||
|
||||
return static_cast<ChatMessage::State>(state);
|
||||
};
|
||||
}
|
||||
|
||||
void MainDb::setChatMessageParticipantState (
|
||||
const shared_ptr<EventLog> &eventLog,
|
||||
const IdentityAddress &participantAddress,
|
||||
ChatMessage::State state
|
||||
) {
|
||||
L_SAFE_TRANSACTION {
|
||||
L_D();
|
||||
|
||||
soci::session *session = d->dbSession.getBackendSession();
|
||||
|
||||
const EventLogPrivate *dEventLog = eventLog->getPrivate();
|
||||
MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
|
||||
const long long &eventId = dEventKey->storageId;
|
||||
const long long &participantSipAddressId = d->selectSipAddressId(participantAddress.asString());
|
||||
int stateInt = static_cast<int>(state);
|
||||
|
||||
*session << "UPDATE chat_message_participant SET state = :state"
|
||||
" WHERE event_id = :eventId AND participant_sip_address_id = :participantSipAddressId",
|
||||
soci::use(stateInt), soci::use(eventId), soci::use(participantSipAddressId);
|
||||
};
|
||||
}
|
||||
|
||||
shared_ptr<ChatMessage> MainDb::getLastChatMessage (const ChatRoomId &chatRoomId) const {
|
||||
list<shared_ptr<EventLog>> chatList = getHistory(chatRoomId, 1, Filter::ConferenceChatMessageFilter);
|
||||
if (chatList.empty())
|
||||
|
|
@ -2181,13 +2317,13 @@ list<shared_ptr<ChatMessage>> MainDb::findChatMessages (
|
|||
const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId);
|
||||
soci::rowset<soci::row> rows = (session->prepare << query, soci::use(imdnMessageId), soci::use(dbChatRoomId));
|
||||
for (const auto &row : rows) {
|
||||
long long eventId = d->resolveId(row, 0);
|
||||
long long eventId = d->dbSession.resolveId(row, 0);
|
||||
shared_ptr<EventLog> event = d->getEventFromCache(eventId);
|
||||
|
||||
if (!event)
|
||||
event = d->selectGenericConferenceEvent(
|
||||
eventId,
|
||||
static_cast<EventLog::Type>(row.get<int>(1)),
|
||||
EventLog::Type(row.get<int>(1)),
|
||||
Utils::getTmAsTimeT(row.get<tm>(2)),
|
||||
chatRoomId
|
||||
);
|
||||
|
|
@ -2229,7 +2365,7 @@ list<shared_ptr<EventLog>> MainDb::getHistoryRange (
|
|||
" SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId"
|
||||
" )";
|
||||
query += buildSqlEventFilter({
|
||||
ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter
|
||||
ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter, ConferenceInfoNoDeviceFilter
|
||||
}, mask, "AND");
|
||||
query += " ORDER BY creation_time DESC";
|
||||
|
||||
|
|
@ -2256,13 +2392,13 @@ list<shared_ptr<EventLog>> MainDb::getHistoryRange (
|
|||
const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId);
|
||||
soci::rowset<soci::row> rows = (session->prepare << query, soci::use(dbChatRoomId));
|
||||
for (const auto &row : rows) {
|
||||
long long eventId = d->resolveId(row, 0);
|
||||
long long eventId = d->dbSession.resolveId(row, 0);
|
||||
shared_ptr<EventLog> event = d->getEventFromCache(eventId);
|
||||
|
||||
if (!event)
|
||||
event = d->selectGenericConferenceEvent(
|
||||
eventId,
|
||||
static_cast<EventLog::Type>(row.get<int>(1)),
|
||||
EventLog::Type(row.get<int>(1)),
|
||||
Utils::getTmAsTimeT(row.get<tm>(2)),
|
||||
chatRoomId
|
||||
);
|
||||
|
|
@ -2281,7 +2417,7 @@ int MainDb::getHistorySize (const ChatRoomId &chatRoomId, FilterMask mask) const
|
|||
const string query = "SELECT COUNT(*) FROM event, conference_event"
|
||||
" WHERE chat_room_id = :chatRoomId"
|
||||
" AND event_id = event.id" + buildSqlEventFilter({
|
||||
ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter
|
||||
ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter, ConferenceInfoNoDeviceFilter
|
||||
}, mask, "AND");
|
||||
|
||||
return L_SAFE_TRANSACTION {
|
||||
|
|
@ -2301,7 +2437,7 @@ int MainDb::getHistorySize (const ChatRoomId &chatRoomId, FilterMask mask) const
|
|||
void MainDb::cleanHistory (const ChatRoomId &chatRoomId, FilterMask mask) {
|
||||
const string query = "SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" +
|
||||
buildSqlEventFilter({
|
||||
ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter
|
||||
ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter, ConferenceInfoNoDeviceFilter
|
||||
}, mask);
|
||||
|
||||
DurationLogger durationLogger(
|
||||
|
|
@ -2322,8 +2458,6 @@ void MainDb::cleanHistory (const ChatRoomId &chatRoomId, FilterMask mask) {
|
|||
*session << "DELETE FROM event WHERE id IN (" + query + ")", soci::use(dbChatRoomId);
|
||||
|
||||
tr.commit();
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -2373,7 +2507,7 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms () const {
|
|||
} else if (capabilities & ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::Conference)) {
|
||||
list<shared_ptr<Participant>> participants;
|
||||
|
||||
const long long &dbChatRoomId = d->resolveId(row, 0);
|
||||
const long long &dbChatRoomId = d->dbSession.resolveId(row, 0);
|
||||
static const string query = "SELECT chat_room_participant.id, sip_address.value, is_admin"
|
||||
" FROM sip_address, chat_room, chat_room_participant"
|
||||
" WHERE chat_room.id = :chatRoomId"
|
||||
|
|
@ -2390,14 +2524,16 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms () const {
|
|||
|
||||
// Fetch devices.
|
||||
{
|
||||
const long long &participantId = d->resolveId(row, 0);
|
||||
static const string query = "SELECT sip_address.value FROM chat_room_participant_device, sip_address"
|
||||
const long long &participantId = d->dbSession.resolveId(row, 0);
|
||||
static const string query = "SELECT sip_address.value, state FROM chat_room_participant_device, sip_address"
|
||||
" WHERE chat_room_participant_id = :participantId"
|
||||
" AND participant_device_sip_address_id = sip_address.id";
|
||||
|
||||
soci::rowset<soci::row> rows = (session->prepare << query, soci::use(participantId));
|
||||
for (const auto &row : rows)
|
||||
dParticipant->addDevice(IdentityAddress(row.get<string>(0)));
|
||||
for (const auto &row : rows) {
|
||||
shared_ptr<ParticipantDevice> device = dParticipant->addDevice(IdentityAddress(row.get<string>(0)));
|
||||
device->setState(ParticipantDevice::State(static_cast<unsigned int>(row.get<int>(1, 0))));
|
||||
}
|
||||
}
|
||||
|
||||
if (participant->getAddress() == chatRoomId.getLocalAddress().getAddressWithoutGruu())
|
||||
|
|
@ -2477,8 +2613,6 @@ void MainDb::insertChatRoom (const shared_ptr<AbstractChatRoom> &chatRoom) {
|
|||
d->insertChatRoom(chatRoom);
|
||||
|
||||
tr.commit();
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -2503,8 +2637,6 @@ void MainDb::deleteChatRoom (const ChatRoomId &chatRoomId) {
|
|||
*session << "DELETE FROM chat_room WHERE id = :chatRoomId", soci::use(dbChatRoomId);
|
||||
|
||||
tr.commit();
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -2530,19 +2662,6 @@ void MainDb::migrateBasicToClientGroupChatRoom (
|
|||
const long long &localSipAddressId = d->insertSipAddress(newChatRoomId.getLocalAddress().asString());
|
||||
const int &capabilities = clientGroupChatRoom->getCapabilities();
|
||||
|
||||
{
|
||||
shared_ptr<AbstractChatRoom> buggyChatRoom = getCore()->findChatRoom(newChatRoomId);
|
||||
if (buggyChatRoom) {
|
||||
lError() << "Chat room was found with the same chat room id of a new migrated ClientGroupChatRoom!!!";
|
||||
AbstractChatRoom::CapabilitiesMask capabilities = buggyChatRoom->getCapabilities();
|
||||
if (capabilities & AbstractChatRoom::Capabilities::Basic) {
|
||||
lError() << "Delete invalid basic chat room...";
|
||||
Core::deleteChatRoom(buggyChatRoom);
|
||||
} else
|
||||
lError() << "Unable to delete invalid chat room with capabilities: " << capabilities << ".";
|
||||
}
|
||||
}
|
||||
|
||||
*session << "UPDATE chat_room"
|
||||
" SET capabilities = :capabilities,"
|
||||
" peer_sip_address_id = :peerSipAddressId,"
|
||||
|
|
@ -2570,8 +2689,6 @@ void MainDb::migrateBasicToClientGroupChatRoom (
|
|||
}
|
||||
|
||||
tr.commit();
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -2666,8 +2783,6 @@ void MainDb::insertOneToOneConferenceChatRoom (const shared_ptr<AbstractChatRoom
|
|||
}
|
||||
|
||||
tr.commit();
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -2684,15 +2799,33 @@ void MainDb::enableChatRoomMigration (const ChatRoomId &chatRoomId, bool enable)
|
|||
*session << "SELECT capabilities FROM chat_room WHERE id = :chatRoomId",
|
||||
soci::use(dbChatRoomId), soci::into(capabilities);
|
||||
if (enable)
|
||||
capabilities |= static_cast<int>(ChatRoom::Capabilities::Migratable);
|
||||
capabilities |= int(ChatRoom::Capabilities::Migratable);
|
||||
else
|
||||
capabilities &= ~static_cast<int>(ChatRoom::Capabilities::Migratable);
|
||||
capabilities &= ~int(ChatRoom::Capabilities::Migratable);
|
||||
*session << "UPDATE chat_room SET capabilities = :capabilities WHERE id = :chatRoomId",
|
||||
soci::use(capabilities), soci::use(dbChatRoomId);
|
||||
|
||||
tr.commit();
|
||||
};
|
||||
}
|
||||
|
||||
return true;
|
||||
void MainDb::updateChatRoomParticipantDevice (const shared_ptr<AbstractChatRoom> &chatRoom, const shared_ptr<ParticipantDevice> &device) {
|
||||
L_SAFE_TRANSACTION {
|
||||
L_D();
|
||||
|
||||
soci::session *session = d->dbSession.getBackendSession();
|
||||
soci::transaction tr(*session);
|
||||
|
||||
const long long &dbChatRoomId = d->selectChatRoomId(chatRoom->getChatRoomId());
|
||||
const long long &participantSipAddressId = d->selectSipAddressId(device->getParticipant()->getAddress().asString());
|
||||
const long long &participantId = d->selectChatRoomParticipantId(dbChatRoomId, participantSipAddressId);
|
||||
const long long &participantSipDeviceAddressId = d->selectSipAddressId(device->getAddress().asString());
|
||||
unsigned int stateInt = static_cast<unsigned int>(device->getState());
|
||||
*session << "UPDATE chat_room_participant_device SET state = :state"
|
||||
" WHERE chat_room_participant_id = :participantId AND participant_device_sip_address_id = :participantSipDeviceAddressId",
|
||||
soci::use(stateInt), soci::use(participantId), soci::use(participantSipDeviceAddressId);
|
||||
|
||||
tr.commit();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -2714,12 +2847,10 @@ bool MainDb::import (Backend, const string ¶meters) {
|
|||
// TODO: Remove condition after cpp migration in friends/friends list.
|
||||
if (false)
|
||||
d->importLegacyFriends(inDbSession);
|
||||
return true;
|
||||
};
|
||||
|
||||
L_SAFE_TRANSACTION {
|
||||
d->importLegacyHistory(inDbSession);
|
||||
return true;
|
||||
};
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "linphone/utils/enum-mask.h"
|
||||
|
||||
#include "abstract/abstract-db.h"
|
||||
#include "chat/chat-message/chat-message.h"
|
||||
#include "chat/chat-room/chat-room-id.h"
|
||||
#include "core/core-accessor.h"
|
||||
|
||||
|
|
@ -38,6 +39,7 @@ class Core;
|
|||
class EventLog;
|
||||
class MainDbKey;
|
||||
class MainDbPrivate;
|
||||
class ParticipantDevice;
|
||||
|
||||
class MainDb : public AbstractDb, public CoreAccessor {
|
||||
friend class MainDbChatMessageKey;
|
||||
|
|
@ -48,7 +50,8 @@ public:
|
|||
NoFilter = 0x0,
|
||||
ConferenceCallFilter = 0x1,
|
||||
ConferenceChatMessageFilter = 0x2,
|
||||
ConferenceInfoFilter = 0x4
|
||||
ConferenceInfoFilter = 0x4,
|
||||
ConferenceInfoNoDeviceFilter = 0x6
|
||||
};
|
||||
|
||||
typedef EnumMask<Filter> FilterMask;
|
||||
|
|
@ -84,6 +87,17 @@ public:
|
|||
void markChatMessagesAsRead (const ChatRoomId &chatRoomId = ChatRoomId()) const;
|
||||
std::list<std::shared_ptr<ChatMessage>> getUnreadChatMessages (const ChatRoomId &chatRoomId = ChatRoomId()) const;
|
||||
|
||||
std::list<ChatMessage::State> getChatMessageParticipantStates (const std::shared_ptr<EventLog> &eventLog) const;
|
||||
ChatMessage::State getChatMessageParticipantState (
|
||||
const std::shared_ptr<EventLog> &eventLog,
|
||||
const IdentityAddress &participantAddress
|
||||
) const;
|
||||
void setChatMessageParticipantState (
|
||||
const std::shared_ptr<EventLog> &eventLog,
|
||||
const IdentityAddress &participantAddress,
|
||||
ChatMessage::State state
|
||||
);
|
||||
|
||||
std::shared_ptr<ChatMessage> getLastChatMessage (const ChatRoomId &chatRoomId) const;
|
||||
|
||||
std::list<std::shared_ptr<ChatMessage>> findChatMessages (
|
||||
|
|
@ -135,6 +149,11 @@ public:
|
|||
) const;
|
||||
void insertOneToOneConferenceChatRoom (const std::shared_ptr<AbstractChatRoom> &chatRoom);
|
||||
|
||||
void updateChatRoomParticipantDevice (
|
||||
const std::shared_ptr<AbstractChatRoom> &chatRoom,
|
||||
const std::shared_ptr<ParticipantDevice> &device
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Other.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ DbSession::DbSession (const string &uri) : DbSession() {
|
|||
#ifdef SOCI_ENABLED
|
||||
try {
|
||||
L_D();
|
||||
d->backendSession = make_unique<soci::session>(uri);
|
||||
d->backendSession = makeUnique<soci::session>(uri);
|
||||
d->backend = !uri.find("mysql") ? DbSessionPrivate::Backend::Mysql : DbSessionPrivate::Backend::Sqlite3;
|
||||
} catch (const exception &e) {
|
||||
lWarning() << "Unable to build db session with uri: " << e.what();
|
||||
|
|
@ -51,12 +51,14 @@ DbSession::operator bool () const {
|
|||
|
||||
L_USE_DEFAULT_CLONABLE_OBJECT_SHARED_IMPL(DbSession);
|
||||
|
||||
#ifdef SOCI_ENABLED
|
||||
soci::session *DbSession::getBackendSession () const {
|
||||
soci::session *DbSession::getBackendSession () const {
|
||||
#ifdef SOCI_ENABLED
|
||||
L_D();
|
||||
return d->backendSession.get();
|
||||
}
|
||||
#endif // ifdef SOCI_ENABLED
|
||||
#else
|
||||
return nullptr;
|
||||
#endif // ifdef SOCI_ENABLED
|
||||
}
|
||||
|
||||
string DbSession::primaryKeyStr (const string &type) const {
|
||||
L_D();
|
||||
|
|
@ -195,10 +197,31 @@ bool DbSession::checkTableExists (const string &table) const {
|
|||
return false;
|
||||
}
|
||||
L_ASSERT(false);
|
||||
#else
|
||||
(void)table;
|
||||
#endif // ifdef SOCI_ENABLED
|
||||
|
||||
(void)table;
|
||||
return false;
|
||||
}
|
||||
|
||||
long long DbSession::resolveId (const soci::row &row, int col) const {
|
||||
#ifdef SOCI_ENABLED
|
||||
L_D();
|
||||
switch (d->backend) {
|
||||
case DbSessionPrivate::Backend::Mysql:
|
||||
return static_cast<long long>(row.get<unsigned long long>(0));
|
||||
case DbSessionPrivate::Backend::Sqlite3:
|
||||
return static_cast<long long>(row.get<int>(0));
|
||||
case DbSessionPrivate::Backend::None:
|
||||
return 0;
|
||||
}
|
||||
L_ASSERT(false);
|
||||
#else
|
||||
(void)row;
|
||||
(void)col;
|
||||
#endif // ifdef SOCI_ENABLED
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LINPHONE_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -28,6 +28,13 @@
|
|||
|
||||
// =============================================================================
|
||||
|
||||
#ifndef SOCI_ENABLED
|
||||
namespace soci {
|
||||
class row;
|
||||
class session;
|
||||
}
|
||||
#endif // ifndef SOCI_ENABLED
|
||||
|
||||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
class DbSessionPrivate;
|
||||
|
|
@ -44,9 +51,7 @@ public:
|
|||
|
||||
operator bool () const;
|
||||
|
||||
#ifdef SOCI_ENABLED
|
||||
soci::session *getBackendSession () const;
|
||||
#endif // ifdef SOCI_ENABLED
|
||||
soci::session *getBackendSession () const;
|
||||
|
||||
std::string primaryKeyStr (const std::string &type = "INT") const;
|
||||
std::string primaryKeyRefStr (const std::string &type = "INT") const;
|
||||
|
|
@ -62,6 +67,8 @@ public:
|
|||
|
||||
bool checkTableExists (const std::string &table) const;
|
||||
|
||||
long long resolveId (const soci::row &row, int col) const;
|
||||
|
||||
private:
|
||||
L_DECLARE_PRIVATE(DbSession);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class DurationLoggerPrivate;
|
|||
|
||||
class DurationLogger : public BaseObject {
|
||||
public:
|
||||
DurationLogger (const std::string &label, Logger::Level level = Logger::Debug);
|
||||
DurationLogger (const std::string &label, Logger::Level level = Logger::Info);
|
||||
~DurationLogger ();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
LINPHONE_BEGIN_NAMESPACE
|
||||
|
||||
void l_assert (const char *condition, const char *file, int line) {
|
||||
void lAssert (const char *condition, const char *file, int line) {
|
||||
lFatal() << "ASSERT: " << condition << " in " << file << " line " << line << ".";
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -888,6 +888,55 @@ static void group_chat_room_remove_admin (void) {
|
|||
linphone_core_manager_destroy(laure);
|
||||
}
|
||||
|
||||
static void group_chat_room_admin_creator_leaves_the_room (void) {
|
||||
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
|
||||
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
|
||||
LinphoneCoreManager *laure = linphone_core_manager_create("laure_tcp_rc");
|
||||
bctbx_list_t *coresManagerList = NULL;
|
||||
bctbx_list_t *participantsAddresses = NULL;
|
||||
coresManagerList = bctbx_list_append(coresManagerList, marie);
|
||||
coresManagerList = bctbx_list_append(coresManagerList, pauline);
|
||||
coresManagerList = bctbx_list_append(coresManagerList, laure);
|
||||
bctbx_list_t *coresList = init_core_for_conference(coresManagerList);
|
||||
start_core_for_conference(coresManagerList);
|
||||
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc)));
|
||||
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(laure->lc)));
|
||||
stats initialMarieStats = marie->stat;
|
||||
stats initialPaulineStats = pauline->stat;
|
||||
stats initialLaureStats = laure->stat;
|
||||
|
||||
// Marie creates a new group chat room
|
||||
const char *initialSubject = "Colleagues";
|
||||
LinphoneChatRoom *marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, -1);
|
||||
|
||||
const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
|
||||
|
||||
// Check that the chat room is correctly created on Pauline's side and that the participants are added
|
||||
LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline, &initialPaulineStats, confAddr, initialSubject, 2, 0);
|
||||
|
||||
// Check that the chat room is correctly created on Laure's side and that the participants are added
|
||||
LinphoneChatRoom *laureCr = check_creation_chat_room_client_side(coresList, laure, &initialLaureStats, confAddr, initialSubject, 2, 0);
|
||||
|
||||
// Marie leaves the room
|
||||
linphone_chat_room_leave(marieCr);
|
||||
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_participants_removed, initialPaulineStats.number_of_participants_removed + 1, 1000));
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_participants_removed, initialLaureStats.number_of_participants_removed + 1, 1000));
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_participant_admin_statuses_changed, initialPaulineStats.number_of_participant_admin_statuses_changed + 1, 1000));
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_participant_admin_statuses_changed, initialLaureStats.number_of_participant_admin_statuses_changed + 1, 1000));
|
||||
BC_ASSERT_TRUE(linphone_participant_is_admin(linphone_chat_room_get_me(laureCr)));
|
||||
|
||||
// Clean db from chat room
|
||||
linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
|
||||
linphone_core_manager_delete_chat_room(laure, laureCr, coresList);
|
||||
linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
|
||||
|
||||
bctbx_list_free(coresList);
|
||||
bctbx_list_free(coresManagerList);
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(laure);
|
||||
}
|
||||
|
||||
static void group_chat_room_change_subject (void) {
|
||||
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
|
||||
|
|
@ -1304,7 +1353,7 @@ static void group_chat_room_create_room_with_disconnected_friends_and_initial_me
|
|||
group_chat_room_create_room_with_disconnected_friends_base(TRUE);
|
||||
}
|
||||
|
||||
static void group_chat_room_reinvited_after_removed_base (bool_t offline_when_removed) {
|
||||
static void group_chat_room_reinvited_after_removed_base (bool_t offline_when_removed, bool_t offline_when_reinvited) {
|
||||
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
|
||||
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
|
||||
LinphoneCoreManager *laure = linphone_core_manager_create("laure_tcp_rc");
|
||||
|
|
@ -1345,35 +1394,50 @@ static void group_chat_room_reinvited_after_removed_base (bool_t offline_when_re
|
|||
|
||||
// Marie removes Laure from the chat room
|
||||
LinphoneParticipant *laureParticipant = linphone_chat_room_find_participant(marieCr, laureAddr);
|
||||
linphone_address_unref(laureAddr);
|
||||
BC_ASSERT_PTR_NOT_NULL(laureParticipant);
|
||||
linphone_chat_room_remove_participant(marieCr, laureParticipant);
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_participants_removed, initialMarieStats.number_of_participants_removed + 1, 1000));
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_participants_removed, initialPaulineStats.number_of_participants_removed + 1, 1000));
|
||||
|
||||
if (offline_when_removed) {
|
||||
if (offline_when_removed && !offline_when_reinvited) {
|
||||
linphone_core_manager_configure(laure);
|
||||
lp_config_set_string(linphone_core_get_config(laure->lc), "misc", "uuid", savedLaureUuid);
|
||||
bctbx_free(savedLaureUuid);
|
||||
bctbx_list_t *tmpCoresManagerList = bctbx_list_append(NULL, laure);
|
||||
init_core_for_conference(tmpCoresManagerList);
|
||||
bctbx_list_free(tmpCoresManagerList);
|
||||
initialLaureStats = laure->stat;
|
||||
linphone_core_manager_start(laure, TRUE);
|
||||
coresList = bctbx_list_append(coresList, laure->lc);
|
||||
coresManagerList = bctbx_list_append(coresManagerList, laure);
|
||||
initialLaureStats = laure->stat;
|
||||
}
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomStateTerminated, initialLaureStats.number_of_LinphoneChatRoomStateTerminated + 1, 3000));
|
||||
if (!offline_when_reinvited)
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &laure->stat.number_of_LinphoneChatRoomStateTerminated, initialLaureStats.number_of_LinphoneChatRoomStateTerminated + 1, 3000));
|
||||
|
||||
// Marie adds Laure to the chat room
|
||||
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(laure->lc)));
|
||||
participantsAddresses = bctbx_list_append(participantsAddresses, laureAddr);
|
||||
linphone_chat_room_add_participants(marieCr, participantsAddresses);
|
||||
bctbx_list_free_with_data(participantsAddresses, (bctbx_list_free_func)linphone_address_unref);
|
||||
participantsAddresses = NULL;
|
||||
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, &marie->stat.number_of_participants_added, initialMarieStats.number_of_participants_added + 1, 1000));
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_participants_added, initialPaulineStats.number_of_participants_added + 1, 1000));
|
||||
if (offline_when_reinvited) {
|
||||
linphone_core_manager_configure(laure);
|
||||
lp_config_set_string(linphone_core_get_config(laure->lc), "misc", "uuid", savedLaureUuid);
|
||||
bctbx_free(savedLaureUuid);
|
||||
bctbx_list_t *tmpCoresManagerList = bctbx_list_append(NULL, laure);
|
||||
init_core_for_conference(tmpCoresManagerList);
|
||||
bctbx_list_free(tmpCoresManagerList);
|
||||
initialLaureStats = laure->stat;
|
||||
linphone_core_manager_start(laure, TRUE);
|
||||
coresList = bctbx_list_append(coresList, laure->lc);
|
||||
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_EQUAL(linphone_chat_room_get_nb_participants(marieCr), 2, int, "%d");
|
||||
BC_ASSERT_EQUAL(linphone_chat_room_get_nb_participants(paulineCr), 2, int, "%d");
|
||||
laureAddr = linphone_address_new(linphone_core_get_device_identity(laure->lc));
|
||||
|
|
@ -1397,11 +1461,15 @@ static void group_chat_room_reinvited_after_removed_base (bool_t offline_when_re
|
|||
}
|
||||
|
||||
static void group_chat_room_reinvited_after_removed (void) {
|
||||
group_chat_room_reinvited_after_removed_base(FALSE);
|
||||
group_chat_room_reinvited_after_removed_base(FALSE, FALSE);
|
||||
}
|
||||
|
||||
static void group_chat_room_reinvited_after_removed_while_offline (void) {
|
||||
group_chat_room_reinvited_after_removed_base(TRUE);
|
||||
group_chat_room_reinvited_after_removed_base(TRUE, FALSE);
|
||||
}
|
||||
|
||||
static void group_chat_room_reinvited_after_removed_while_offline_2 (void) {
|
||||
group_chat_room_reinvited_after_removed_base(TRUE, TRUE);
|
||||
}
|
||||
|
||||
static void group_chat_room_notify_after_disconnection (void) {
|
||||
|
|
@ -2546,6 +2614,79 @@ static void group_chat_room_new_unique_one_to_one_chat_room_after_both_participa
|
|||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
static void imdn_for_group_chat_room (void) {
|
||||
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
|
||||
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
|
||||
LinphoneCoreManager *chloe = linphone_core_manager_create("chloe_rc");
|
||||
bctbx_list_t *coresManagerList = NULL;
|
||||
bctbx_list_t *participantsAddresses = NULL;
|
||||
coresManagerList = bctbx_list_append(coresManagerList, marie);
|
||||
coresManagerList = bctbx_list_append(coresManagerList, pauline);
|
||||
coresManagerList = bctbx_list_append(coresManagerList, chloe);
|
||||
bctbx_list_t *coresList = init_core_for_conference(coresManagerList);
|
||||
start_core_for_conference(coresManagerList);
|
||||
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc)));
|
||||
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(chloe->lc)));
|
||||
stats initialMarieStats = marie->stat;
|
||||
stats initialPaulineStats = pauline->stat;
|
||||
stats initialChloeStats = chloe->stat;
|
||||
|
||||
// Enable IMDN
|
||||
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc));
|
||||
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc));
|
||||
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(chloe->lc));
|
||||
linphone_config_set_bool(linphone_core_get_config(marie->lc), "misc", "enable_simple_group_chat_message_state", FALSE);
|
||||
linphone_config_set_bool(linphone_core_get_config(pauline->lc), "misc", "enable_simple_group_chat_message_state", FALSE);
|
||||
linphone_config_set_bool(linphone_core_get_config(chloe->lc), "misc", "enable_simple_group_chat_message_state", FALSE);
|
||||
|
||||
// Marie creates a new group chat room
|
||||
const char *initialSubject = "Colleagues";
|
||||
LinphoneChatRoom *marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, -1);
|
||||
const LinphoneAddress *confAddr = linphone_chat_room_get_conference_address(marieCr);
|
||||
|
||||
// Check that the chat room is correctly created on Pauline's side and that the participants are added
|
||||
LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline, &initialPaulineStats, confAddr, initialSubject, 2, 0);
|
||||
|
||||
// Check that the chat room is correctly created on Chloe's side and that the participants are added
|
||||
LinphoneChatRoom *chloeCr = check_creation_chat_room_client_side(coresList, chloe, &initialChloeStats, confAddr, initialSubject, 2, 0);
|
||||
|
||||
// Chloe begins composing a message
|
||||
const char *chloeMessage = "Hello";
|
||||
_send_message(chloeCr, chloeMessage);
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageReceived, initialMarieStats.number_of_LinphoneMessageReceived + 1, 10000));
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 1, 10000));
|
||||
LinphoneChatMessage *marieLastMsg = marie->stat.last_received_chat_message;
|
||||
if (!BC_ASSERT_PTR_NOT_NULL(marieLastMsg))
|
||||
goto end;
|
||||
BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(marieLastMsg), chloeMessage);
|
||||
LinphoneAddress *chloeAddr = linphone_address_new(linphone_core_get_identity(chloe->lc));
|
||||
BC_ASSERT_TRUE(linphone_address_weak_equal(chloeAddr, linphone_chat_message_get_from_address(marieLastMsg)));
|
||||
linphone_address_unref(chloeAddr);
|
||||
|
||||
// Check that the message has been delivered to Marie and Pauline
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &chloe->stat.number_of_LinphoneMessageDeliveredToUser, initialChloeStats.number_of_LinphoneMessageDeliveredToUser + 1, 10000));
|
||||
|
||||
// Marie marks the message as read, check that the state is not yet displayed on Chloe's side
|
||||
linphone_chat_room_mark_as_read(marieCr);
|
||||
BC_ASSERT_FALSE(wait_for_list(coresList, &chloe->stat.number_of_LinphoneMessageDisplayed, initialChloeStats.number_of_LinphoneMessageDisplayed + 1, 1000));
|
||||
|
||||
// Pauline also marks the message as read, check that the state is now displayed on Chloe's side
|
||||
linphone_chat_room_mark_as_read(paulineCr);
|
||||
BC_ASSERT_TRUE(wait_for_list(coresList, &chloe->stat.number_of_LinphoneMessageDisplayed, initialChloeStats.number_of_LinphoneMessageDisplayed + 1, 1000));
|
||||
|
||||
end:
|
||||
// Clean db from chat room
|
||||
linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
|
||||
linphone_core_manager_delete_chat_room(chloe, chloeCr, coresList);
|
||||
linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
|
||||
|
||||
bctbx_list_free(coresList);
|
||||
bctbx_list_free(coresManagerList);
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
linphone_core_manager_destroy(chloe);
|
||||
}
|
||||
|
||||
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"),
|
||||
|
|
@ -2555,6 +2696,7 @@ test_t group_chat_tests[] = {
|
|||
TEST_TWO_TAGS("Add admin lately notified", group_chat_room_add_admin_lately_notified, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Add admin with a non admin", group_chat_room_add_admin_non_admin, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Remove admin", group_chat_room_remove_admin, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Admin creator leaves the room", group_chat_room_admin_creator_leaves_the_room, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Change subject", group_chat_room_change_subject, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Change subject with a non admin", group_chat_room_change_subject_non_admin, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Remove participant", group_chat_room_remove_participant, "Server", "LeaksMemory"),
|
||||
|
|
@ -2565,6 +2707,7 @@ test_t group_chat_tests[] = {
|
|||
TEST_TWO_TAGS("Create chat room with disconnected friends and initial message", group_chat_room_create_room_with_disconnected_friends_and_initial_message, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Reinvited after removed from group chat room", group_chat_room_reinvited_after_removed, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Reinvited after removed from group chat room while offline", group_chat_room_reinvited_after_removed_while_offline, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Reinvited after removed from group chat room while offline 2", group_chat_room_reinvited_after_removed_while_offline_2, "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"),
|
||||
// TODO: Use when we support adding a new device in created conf
|
||||
|
|
@ -2581,7 +2724,8 @@ test_t group_chat_tests[] = {
|
|||
TEST_TWO_TAGS("Unique one-to-one chatroom", group_chat_room_unique_one_to_one_chat_room, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("Unique one-to-one chatroom recreated from message", group_chat_room_unique_one_to_one_chat_room_recreated_from_message, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("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, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("New unique one-to-one chatroom after both participants left", group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left, "Server", "LeaksMemory")
|
||||
TEST_TWO_TAGS("New unique one-to-one chatroom after both participants left", group_chat_room_new_unique_one_to_one_chat_room_after_both_participants_left, "Server", "LeaksMemory"),
|
||||
TEST_TWO_TAGS("IMDN for group chat room", imdn_for_group_chat_room, "Server", "LeaksMemory")
|
||||
};
|
||||
|
||||
test_suite_t group_chat_test_suite = {
|
||||
|
|
|
|||
|
|
@ -1709,6 +1709,7 @@ static void real_time_text(bool_t audio_stream_enabled, bool_t srtp_enabled, boo
|
|||
}
|
||||
linphone_chat_room_send_chat_message(pauline_chat_room, rtt_message);
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1));
|
||||
linphone_chat_message_unref(rtt_message);
|
||||
|
||||
if (sql_storage) {
|
||||
bctbx_list_t *marie_messages = linphone_chat_room_get_history(marie_chat_room, 0);
|
||||
|
|
@ -1827,6 +1828,8 @@ static void real_time_text_conversation(void) {
|
|||
}
|
||||
}
|
||||
|
||||
linphone_chat_message_unref(pauline_rtt_message);
|
||||
linphone_chat_message_unref(marie_rtt_message);
|
||||
reset_counters(&pauline->stat);
|
||||
reset_counters(&marie->stat);
|
||||
pauline_rtt_message = linphone_chat_room_create_message(pauline_chat_room,NULL);
|
||||
|
|
@ -1862,6 +1865,8 @@ static void real_time_text_conversation(void) {
|
|||
BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(msg), message2_2);
|
||||
}
|
||||
}
|
||||
linphone_chat_message_unref(pauline_rtt_message);
|
||||
linphone_chat_message_unref(marie_rtt_message);
|
||||
}
|
||||
end_call(marie, pauline);
|
||||
linphone_call_params_unref(marie_params);
|
||||
|
|
@ -1978,7 +1983,14 @@ static void real_time_text_message_accented_chars(void) {
|
|||
|
||||
linphone_chat_room_send_chat_message(pauline_chat_room, rtt_message);
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1));
|
||||
BC_ASSERT_EQUAL(strcmp(linphone_chat_message_get_text(marie->stat.last_received_chat_message), "ãæçéîøùÿ"), 0, int, "%i");
|
||||
BC_ASSERT_PTR_NOT_NULL(marie->stat.last_received_chat_message);
|
||||
if (marie->stat.last_received_chat_message) {
|
||||
const char *text = linphone_chat_message_get_text(marie->stat.last_received_chat_message);
|
||||
BC_ASSERT_PTR_NOT_NULL(text);
|
||||
if (text)
|
||||
BC_ASSERT_STRING_EQUAL(text, "ãæçéîøùÿ");
|
||||
}
|
||||
linphone_chat_message_unref(rtt_message);
|
||||
}
|
||||
end_call(marie, pauline);
|
||||
}
|
||||
|
|
@ -2031,6 +2043,7 @@ static void real_time_text_copy_paste(void) {
|
|||
}
|
||||
linphone_chat_room_send_chat_message(pauline_chat_room, rtt_message);
|
||||
BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneMessageReceived, 1));
|
||||
linphone_chat_message_unref(rtt_message);
|
||||
}
|
||||
|
||||
end_call(marie, pauline);
|
||||
|
|
@ -2269,6 +2282,52 @@ void im_encryption_engine_b64_async(void) {
|
|||
im_encryption_engine_b64_base(TRUE);
|
||||
}
|
||||
|
||||
void unread_message_count(void) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
|
||||
text_message_base(marie, pauline);
|
||||
|
||||
BC_ASSERT_PTR_NOT_NULL(marie->stat.last_received_chat_message);
|
||||
if (marie->stat.last_received_chat_message != NULL) {
|
||||
LinphoneChatRoom *marie_room = linphone_chat_message_get_chat_room(marie->stat.last_received_chat_message);
|
||||
BC_ASSERT_EQUAL(1, linphone_chat_room_get_unread_messages_count(marie_room), int, "%d");
|
||||
linphone_chat_room_mark_as_read(marie_room);
|
||||
BC_ASSERT_EQUAL(0, linphone_chat_room_get_unread_messages_count(marie_room), int, "%d");
|
||||
}
|
||||
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
static void message_received_callback(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* msg) {
|
||||
BC_ASSERT_PTR_NOT_NULL(room);
|
||||
BC_ASSERT_EQUAL(1, linphone_chat_room_get_unread_messages_count(room), int, "%d");
|
||||
BC_ASSERT_PTR_NOT_NULL(msg);
|
||||
if (room != NULL) {
|
||||
linphone_chat_room_mark_as_read(room);
|
||||
}
|
||||
BC_ASSERT_EQUAL(0, linphone_chat_room_get_unread_messages_count(room), int, "%d");
|
||||
}
|
||||
|
||||
void unread_message_count_callback(void) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
|
||||
int dummy = 0;
|
||||
|
||||
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
|
||||
linphone_core_cbs_set_message_received(cbs, message_received_callback);
|
||||
linphone_core_add_callbacks(marie->lc, cbs);
|
||||
|
||||
text_message_base(marie, pauline);
|
||||
|
||||
wait_for_until(pauline->lc, marie->lc, &dummy, 1, 5000);
|
||||
|
||||
linphone_core_cbs_unref(cbs);
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
test_t message_tests[] = {
|
||||
TEST_NO_TAG("Text message", text_message),
|
||||
TEST_NO_TAG("Text message with credentials from auth callback", text_message_with_credential_from_auth_callback),
|
||||
|
|
@ -2292,6 +2351,8 @@ test_t message_tests[] = {
|
|||
TEST_NO_TAG("IMDN notifications", imdn_notifications),
|
||||
TEST_NO_TAG("IM notification policy", im_notification_policy),
|
||||
#ifdef SQLITE_STORAGE_ENABLED
|
||||
TEST_NO_TAG("Unread message count", unread_message_count),
|
||||
TEST_NO_TAG("Unread message count in callback", unread_message_count_callback),
|
||||
TEST_ONE_TAG("IsComposing notification lime", is_composing_notification_with_lime, "LIME"),
|
||||
TEST_ONE_TAG("IMDN notifications with lime", imdn_notifications_with_lime, "LIME"),
|
||||
TEST_ONE_TAG("IM notification policy with lime", im_notification_policy_with_lime, "LIME"),
|
||||
|
|
|
|||
|
|
@ -357,27 +357,47 @@ static {{return}} {{callbackName}}({{params}}) {
|
|||
{{#interfaces}}
|
||||
{{#isSingleListener}}
|
||||
void Java_{{jniPackage}}{{className}}Impl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) {
|
||||
{{classCName}} *cptr = ({{classCName}}*)ptr;
|
||||
{{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks(cptr);
|
||||
if (jlistener == NULL) {
|
||||
jobject listener = (jobject) {{cPrefix}}_cbs_get_user_data(cbs);
|
||||
{{cPrefix}}_cbs_set_user_data(cbs, NULL);
|
||||
if (listener != NULL) {
|
||||
env->DeleteGlobalRef(listener);
|
||||
}
|
||||
} else {
|
||||
jobject listener = (jobject) {{cPrefix}}_cbs_get_user_data(cbs);
|
||||
if (listener == NULL) {
|
||||
listener = env->NewGlobalRef(jlistener);
|
||||
} else {
|
||||
if (env->IsSameObject(listener, jlistener)) {
|
||||
return;
|
||||
} else {
|
||||
env->DeleteGlobalRef(listener);
|
||||
listener = env->NewGlobalRef(jlistener);
|
||||
}
|
||||
}
|
||||
{{cPrefix}}_cbs_set_user_data(cbs, listener);
|
||||
{{#callbacksList}}
|
||||
{{cPrefix}}_cbs_set_{{callback}}(cbs, {{callbackName}});
|
||||
{{/callbacksList}}
|
||||
}
|
||||
}
|
||||
{{/isSingleListener}}
|
||||
|
||||
{{#isMultiListener}}
|
||||
void Java_{{jniPackage}}{{className}}Impl_addListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) {
|
||||
{{/isMultiListener}}
|
||||
if (jlistener == NULL) return;
|
||||
{{classCName}} *cptr = ({{classCName}}*)ptr;
|
||||
jobject listener = env->NewGlobalRef(jlistener);
|
||||
{{#isSingleListener}}
|
||||
{{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks(cptr);
|
||||
{{/isSingleListener}}
|
||||
{{#isMultiListener}}
|
||||
{{classCName}}Cbs *cbs = linphone_factory_create_{{factoryName}}_cbs(NULL);
|
||||
{{/isMultiListener}}
|
||||
{{cPrefix}}_cbs_set_user_data(cbs, listener);
|
||||
{{#callbacksList}}
|
||||
{{cPrefix}}_cbs_set_{{callback}}(cbs, {{callbackName}});
|
||||
{{/callbacksList}}
|
||||
{{#isMultiListener}}
|
||||
{{cPrefix}}_add_callbacks(cptr, cbs);
|
||||
{{/isMultiListener}}
|
||||
{{cPrefix}}_cbs_unref(cbs);
|
||||
}
|
||||
{{#isMultiListener}}
|
||||
|
||||
void Java_{{jniPackage}}{{className}}Impl_removeListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) {
|
||||
{{classCName}} *cptr = ({{classCName}}*)ptr;
|
||||
|
|
@ -385,14 +405,16 @@ void Java_{{jniPackage}}{{className}}Impl_removeListener(JNIEnv* env, jobject th
|
|||
bctbx_list_t *it;
|
||||
for (it = (bctbx_list_t *)cbs_list; it != NULL; it = it->next) {
|
||||
{{classCName}}Cbs *cbs = ({{classCName}}Cbs *)it->data;
|
||||
if ({{cPrefix}}_cbs_get_user_data(cbs) == jlistener) {
|
||||
jobject listener = (jobject) {{cPrefix}}_cbs_get_user_data(cbs);
|
||||
if (env->IsSameObject(listener, jlistener)) {
|
||||
{{cPrefix}}_cbs_set_user_data(cbs, NULL);
|
||||
{{cPrefix}}_remove_callbacks(cptr, cbs);
|
||||
env->DeleteGlobalRef(listener);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
{{/isMultiListener}}
|
||||
|
||||
{{/interfaces}}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue