Merge branch 'dev_refactor_cpp' into dev_refactor_cpp_search_bar

This commit is contained in:
Erwan Croze 2018-02-16 15:18:48 +01:00
commit f99300cba5
73 changed files with 1489 additions and 839 deletions

View file

@ -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;
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -27,8 +27,6 @@ typedef struct StunCandidate StunCandidate;
typedef struct _PortConfig PortConfig;
typedef struct _LinphoneChatMessageCharacter LinphoneChatMessageCharacter;
typedef struct _LinphoneFriendPresence LinphoneFriendPresence;
typedef struct _LinphoneFriendPhoneNumberSipUri LinphoneFriendPhoneNumberSipUri;

View file

@ -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);
/**
* @}
**/

View file

@ -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);
/**
* @}
*/

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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) {

View file

@ -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));
}

View file

@ -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;
}

View file

@ -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

View file

@ -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<

View file

@ -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);
};

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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 {

View file

@ -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 {

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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
) {

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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:

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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 &
) {}

View file

@ -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();
}

View file

@ -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());

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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 {

View file

@ -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());
}
// -----------------------------------------------------------------------------

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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) {

View file

@ -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.

View file

@ -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 &parameters) {
// 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;

View file

@ -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.
// ---------------------------------------------------------------------------

View file

@ -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

View file

@ -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);
};

View file

@ -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:

View file

@ -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.

View file

@ -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 = {

View file

@ -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"),

View file

@ -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}}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////