Commit 532c64bf authored by Ghislain MARY's avatar Ghislain MARY

Add API to get the imdn state of a chat message for each participant.

parent 291bf82b
......@@ -89,6 +89,7 @@ set(C_API_HEADER_FILES
c-event-log.h
c-magic-search.h
c-participant.h
c-participant-imdn-state.h
c-search-result.h
c-types.h
)
......
......@@ -34,6 +34,7 @@
#include "linphone/api/c-dial-plan.h"
#include "linphone/api/c-event-log.h"
#include "linphone/api/c-participant.h"
#include "linphone/api/c-participant-imdn-state.h"
#include "linphone/api/c-magic-search.h"
#include "linphone/api/c-search-result.h"
#include "linphone/api/c-types.h"
......
......@@ -369,7 +369,26 @@ LINPHONE_PUBLIC const char* linphone_chat_message_get_text_content(const Linphon
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer_in_progress(LinphoneChatMessage *msg);
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_in_state (const LinphoneChatMessage *msg, const LinphoneChatMessageState state);
/**
* Gets the list of participants that displayed this message and the time at which they did.
* @param[in] msg LinphoneChatMessage object
* @return \bctbx_list{LinphoneParticipantImdnState}
*/
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_that_have_displayed (const LinphoneChatMessage *msg);
/**
* Gets the list of participants that did not receive this message.
* @param[in] msg LinphoneChatMessage object
* @return \bctbx_list{LinphoneParticipantImdnState}
*/
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_that_have_not_received (const LinphoneChatMessage *msg);
/**
* Gets the list of participants that received this message and the time at which they did.
* @param[in] msg LinphoneChatMessage object
* @return \bctbx_list{LinphoneParticipantImdnState}
*/
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_that_have_received (const LinphoneChatMessage *msg);
/**
* @}
......
/*
* c-participant-imdn-state.h
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_C_PARTICIPANT_IMDN_STATE_H_
#define _L_C_PARTICIPANT_IMDN_STATE_H_
#include "linphone/api/c-types.h"
// =============================================================================
#ifdef __cplusplus
extern "C" {
#endif // ifdef __cplusplus
/**
* @addtogroup misc
* @{
*/
/**
* Increment reference count of LinphoneParticipantImdnState object.
**/
LINPHONE_PUBLIC LinphoneParticipantImdnState *linphone_participant_imdn_state_ref (LinphoneParticipantImdnState *state);
/**
* Decrement reference count of LinphoneParticipantImdnState object.
**/
LINPHONE_PUBLIC void linphone_participant_imdn_state_unref (LinphoneParticipantImdnState *state);
/**
* Retrieve the user pointer associated with a LinphoneParticipantImdnState.
* @param[in] state A LinphoneParticipantImdnState object
* @return The user pointer associated with the LinphoneParticipantImdnState.
**/
LINPHONE_PUBLIC void *linphone_participant_imdn_state_get_user_data(const LinphoneParticipantImdnState *state);
/**
* Assign a user pointer to a LinphoneParticipantImdnState.
* @param[in] state A LinphoneParticipantImdnState object
* @param[in] ud The user pointer to associate with the LinphoneParticipantImdnState
**/
LINPHONE_PUBLIC void linphone_participant_imdn_state_set_user_data(LinphoneParticipantImdnState *state, void *ud);
/**
* Get the participant concerned by a LinphoneParticipantImdnState.
* @param[in] state A LinphoneParticipantImdnState object
* @return The participant concerned by the LinphoneParticipantImdnState
*/
LINPHONE_PUBLIC const LinphoneParticipant *linphone_participant_imdn_state_get_participant (
const LinphoneParticipantImdnState *state
);
/**
* Get the chat message state the participant is in.
* @param state A LinphoneParticipantImdnState object
* @return The chat message state the participant is in
*/
LINPHONE_PUBLIC LinphoneChatMessageState linphone_participant_imdn_state_get_state (const LinphoneParticipantImdnState *state);
/**
* Get the timestamp at which a participant has reached the state described by a LinphoneParticipantImdnState.
* @param[in] state A LinphoneParticipantImdnState object
* @return The timestamp at which the participant has reached the state described in the LinphoneParticipantImdnState
*/
LINPHONE_PUBLIC time_t linphone_participant_imdn_state_get_state_change_time (const LinphoneParticipantImdnState *state);
/**
* @}
*/
#ifdef __cplusplus
}
#endif // ifdef __cplusplus
#endif // ifndef _L_C_PARTICIPANT_IMDN_STATE_H_
......@@ -162,6 +162,12 @@ typedef struct _LinphoneMagicSearch LinphoneMagicSearch;
**/
typedef struct _LinphoneParticipant LinphoneParticipant;
/**
* The LinphoneParticipantImdnState object represents the state of chat message for a participant of a conference chat room.
* @ingroup misc
**/
typedef struct _LinphoneParticipantImdnState LinphoneParticipantImdnState;
/**
* The LinphoneSearchResult object represents a result of a search
* @ingroup misc
......
......@@ -82,6 +82,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
conference/params/media-session-params-p.h
conference/params/media-session-params.h
conference/participant-device.h
conference/participant-imdn-state.h
conference/participant-imdn-state-p.h
conference/participant-p.h
conference/participant.h
conference/remote-conference-p.h
......@@ -177,6 +179,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
c-wrapper/api/c-event-log.cpp
c-wrapper/api/c-magic-search.cpp
c-wrapper/api/c-participant.cpp
c-wrapper/api/c-participant-imdn-state.cpp
c-wrapper/api/c-search-result.cpp
c-wrapper/internal/c-sal.cpp
c-wrapper/internal/c-tools.cpp
......@@ -212,6 +215,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
conference/params/call-session-params.cpp
conference/params/media-session-params.cpp
conference/participant-device.cpp
conference/participant-imdn-state.cpp
conference/participant.cpp
conference/remote-conference.cpp
conference/session/call-session.cpp
......
......@@ -32,6 +32,7 @@
#include "content/content-type.h"
#include "content/content.h"
#include "conference/participant.h"
#include "conference/participant-imdn-state.h"
// =============================================================================
......@@ -247,10 +248,19 @@ bool_t linphone_chat_message_is_file_transfer_in_progress(LinphoneChatMessage *m
return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isFileTransferInProgress();
}
bctbx_list_t *linphone_chat_message_get_participants_in_state (const LinphoneChatMessage *msg, const LinphoneChatMessageState state) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_PRIVATE_FROM_C_OBJECT(msg)->getParticipantsInState((LinphonePrivate::ChatMessage::State) state));
bctbx_list_t *linphone_chat_message_get_participants_that_have_displayed (const LinphoneChatMessage *msg) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsThatHaveDisplayed());
}
bctbx_list_t *linphone_chat_message_get_participants_that_have_not_received (const LinphoneChatMessage *msg) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsThatHaveNotReceived());
}
bctbx_list_t *linphone_chat_message_get_participants_that_have_received (const LinphoneChatMessage *msg) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsThatHaveReceived());
}
// =============================================================================
// Old listener
// =============================================================================
......
/*
* c-participant-imdn-state.cpp
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/api/c-participant-imdn-state.h"
#include "c-wrapper/c-wrapper.h"
#include "conference/participant.h"
#include "conference/participant-imdn-state.h"
// =============================================================================
using namespace std;
L_DECLARE_C_CLONABLE_OBJECT_IMPL(ParticipantImdnState);
LinphoneParticipantImdnState *linphone_participant_imdn_state_ref (LinphoneParticipantImdnState *state) {
belle_sip_object_ref(state);
return state;
}
void linphone_participant_imdn_state_unref (LinphoneParticipantImdnState *state) {
belle_sip_object_unref(state);
}
void *linphone_participant_imdn_state_get_user_data(const LinphoneParticipantImdnState *state) {
return L_GET_USER_DATA_FROM_C_OBJECT(state);
}
void linphone_participant_imdn_state_set_user_data(LinphoneParticipantImdnState *state, void *ud) {
L_SET_USER_DATA_FROM_C_OBJECT(state, ud);
}
const LinphoneParticipant *linphone_participant_imdn_state_get_participant (const LinphoneParticipantImdnState *state) {
return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(state)->getParticipant());
}
LinphoneChatMessageState linphone_participant_imdn_state_get_state (const LinphoneParticipantImdnState *state) {
return (LinphoneChatMessageState)L_GET_CPP_PTR_FROM_C_OBJECT(state)->getState();
}
time_t linphone_participant_imdn_state_get_state_change_time (const LinphoneParticipantImdnState *state) {
return L_GET_CPP_PTR_FROM_C_OBJECT(state)->getStateChangeTime();
}
......@@ -42,6 +42,7 @@
F(MagicSearch, MagicSearch) \
F(MediaSessionParams, CallParams) \
F(Participant, Participant) \
F(ParticipantImdnState, ParticipantImdnState) \
F(SearchResult, SearchResult)
#define L_REGISTER_SUBTYPES(F) \
......
......@@ -30,6 +30,7 @@
#include "content/content.h"
#include "content/file-content.h"
#include "content/file-transfer-content.h"
#include "db/main-db.h"
#include "db/main-db-chat-message-key.h"
#include "event-log/conference/conference-chat-message-event.h"
#include "object/object-p.h"
......@@ -58,8 +59,8 @@ public:
void setDirection (ChatMessage::Direction dir);
std::list<ParticipantImdnState> getParticipantsByImdnState (MainDb::ParticipantStateRetrievalFunc func) const;
void setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState, time_t stateChangeTime);
std::list<std::shared_ptr<Participant>> getParticipantsInState (const ChatMessage::State state) const;
void setState (ChatMessage::State newState, bool force = false);
void setTime (time_t time);
......
......@@ -35,6 +35,7 @@
#include "chat/modifier/file-transfer-chat-message-modifier.h"
#include "chat/modifier/multipart-chat-message-modifier.h"
#include "conference/participant.h"
#include "conference/participant-imdn-state.h"
#include "content/file-content.h"
#include "content/content.h"
#include "core/core.h"
......@@ -70,6 +71,25 @@ void ChatMessagePrivate::setIsReadOnly (bool readOnly) {
isReadOnly = readOnly;
}
list<ParticipantImdnState> ChatMessagePrivate::getParticipantsByImdnState (MainDb::ParticipantStateRetrievalFunc func) const {
L_Q();
list<ParticipantImdnState> result;
if (!(q->getChatRoom()->getCapabilities() & AbstractChatRoom::Capabilities::Conference) || !dbKey.isValid())
return result;
unique_ptr<MainDb> &mainDb = q->getChatRoom()->getCore()->getPrivate()->mainDb;
shared_ptr<EventLog> eventLog = mainDb->getEventFromKey(dbKey);
list<MainDb::ParticipantState> dbResults = func(eventLog);
for (const auto &dbResult : dbResults) {
auto participant = q->getChatRoom()->findParticipant(dbResult.address);
if (participant)
result.emplace_back(participant, dbResult.state, dbResult.timestamp);
}
return result;
}
void ChatMessagePrivate::setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState, time_t stateChangeTime) {
L_Q();
......@@ -123,29 +143,6 @@ void ChatMessagePrivate::setParticipantState (const IdentityAddress &participant
setState(ChatMessage::State::DeliveredToUser);
}
list<shared_ptr<Participant>> ChatMessagePrivate::getParticipantsInState (const ChatMessage::State state) const {
L_Q();
list<shared_ptr<Participant>> participantsInState;
if (!(q->getChatRoom()->getCapabilities() & AbstractChatRoom::Capabilities::Conference) || !dbKey.isValid()) {
return participantsInState;
}
unique_ptr<MainDb> &mainDb = q->getChatRoom()->getCore()->getPrivate()->mainDb;
shared_ptr<EventLog> eventLog = mainDb->getEventFromKey(dbKey);
list<IdentityAddress> addressesInState = mainDb->getChatMessageParticipantsInState(eventLog, state);
const list<shared_ptr<Participant>> &participants = q->getChatRoom()->getParticipants();
for (IdentityAddress addr : addressesInState) {
for (const auto &participant : participants) {
if (participant->getAddress() == addr) {
participantsInState.push_back(participant);
}
}
}
return participantsInState;
}
void ChatMessagePrivate::setState (ChatMessage::State newState, bool force) {
L_Q();
......@@ -997,6 +994,29 @@ void ChatMessage::setToBeStored (bool value) {
// -----------------------------------------------------------------------------
list<ParticipantImdnState> ChatMessage::getParticipantsThatHaveDisplayed () const {
L_D();
unique_ptr<MainDb> &mainDb = getChatRoom()->getCore()->getPrivate()->mainDb;
auto func = bind(&MainDb::getChatMessageParticipantsThatHaveDisplayed, mainDb.get(), std::placeholders::_1);
return d->getParticipantsByImdnState(func);
}
list<ParticipantImdnState> ChatMessage::getParticipantsThatHaveNotReceived () const {
L_D();
unique_ptr<MainDb> &mainDb = getChatRoom()->getCore()->getPrivate()->mainDb;
auto func = bind(&MainDb::getChatMessageParticipantsThatHaveNotReceived, mainDb.get(), std::placeholders::_1);
return d->getParticipantsByImdnState(func);
}
list<ParticipantImdnState> ChatMessage::getParticipantsThatHaveReceived () const {
L_D();
unique_ptr<MainDb> &mainDb = getChatRoom()->getCore()->getPrivate()->mainDb;
auto func = bind(&MainDb::getChatMessageParticipantsThatHaveReceived, mainDb.get(), std::placeholders::_1);
return d->getParticipantsByImdnState(func);
}
// -----------------------------------------------------------------------------
const LinphoneErrorInfo *ChatMessage::getErrorInfo () const {
L_D();
if (!d->errorInfo) d->errorInfo = linphone_error_info_new(); // let's do it mutable
......
......@@ -40,6 +40,7 @@ class Content;
class FileTransferContent;
class ChatMessagePrivate;
class Participant;
class ParticipantImdnState;
class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor {
friend class BasicToClientGroupChatRoom;
......@@ -94,6 +95,10 @@ public:
bool getToBeStored () const;
void setToBeStored (bool value);
std::list<ParticipantImdnState> getParticipantsThatHaveDisplayed () const;
std::list<ParticipantImdnState> getParticipantsThatHaveReceived () const;
std::list<ParticipantImdnState> getParticipantsThatHaveNotReceived () const;
const std::list<Content *> &getContents () const;
void addContent (Content &content);
void removeContent (const Content &content);
......
/*
* participant-imdn-state-p.h
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_PARTICIPANT_IMDN_STATE_P_H_
#define _L_PARTICIPANT_IMDN_STATE_P_H_
#include "object/clonable-object-p.h"
#include "conference/participant-imdn-state.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ParticipantImdnStatePrivate : public ClonableObjectPrivate {
public:
std::shared_ptr<Participant> participant;
ChatMessage::State state = ChatMessage::State::Idle;
time_t stateChangeTime = 0;
L_DECLARE_PUBLIC(ParticipantImdnState);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_PARTICIPANT_IMDN_STATE_P_H_
/*
* participant-imdn-state.cpp
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "participant-imdn-state-p.h"
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// =============================================================================
ParticipantImdnState::ParticipantImdnState (const shared_ptr<Participant> &participant, ChatMessage::State state, time_t stateChangeTime)
: ClonableObject(*new ParticipantImdnStatePrivate)
{
L_D();
d->participant = participant;
d->state = state;
d->stateChangeTime = stateChangeTime;
}
ParticipantImdnState::ParticipantImdnState(const ParticipantImdnState &other) : ClonableObject(*new ParticipantImdnStatePrivate) {
L_D();
d->participant = other.getParticipant();
d->state = other.getState();
d->stateChangeTime = other.getStateChangeTime();
}
// -----------------------------------------------------------------------------
shared_ptr<Participant> ParticipantImdnState::getParticipant () const {
L_D();
return d->participant;
}
ChatMessage::State ParticipantImdnState::getState () const {
L_D();
return d->state;
}
time_t ParticipantImdnState::getStateChangeTime () const {
L_D();
return d->stateChangeTime;
}
LINPHONE_END_NAMESPACE
/*
* participant-imdn-state.h
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_PARTICIPANT_IMDN_STATE_H_
#define _L_PARTICIPANT_IMDN_STATE_H_
#include "chat/chat-message/chat-message.h"
#include "object/clonable-object.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class Participant;
class ParticipantImdnStatePrivate;
class ParticipantImdnState : public ClonableObject {
public:
ParticipantImdnState (const std::shared_ptr<Participant> &participant, ChatMessage::State state, time_t stateChangeTime);
ParticipantImdnState (const ParticipantImdnState &other);
std::shared_ptr<Participant> getParticipant () const;
ChatMessage::State getState () const;
time_t getStateChangeTime () const;
private:
L_DECLARE_PRIVATE(ParticipantImdnState);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_PARTICIPANT_IMDN_STATE_H_
......@@ -44,6 +44,7 @@ class LINPHONE_PUBLIC Core : public Object {
friend class BasicToClientGroupChatRoomPrivate;
friend class CallPrivate;
friend class CallSession;
friend class ChatMessage;
friend class ChatMessagePrivate;
friend class ChatRoom;
friend class ChatRoomPrivate;
......
......@@ -1930,50 +1930,105 @@ list<shared_ptr<ChatMessage>> MainDb::getUnreadChatMessages (const ChatRoomId &c
};
}
list<ChatMessage::State> MainDb::getChatMessageParticipantStates (const shared_ptr<EventLog> &eventLog) const {
list<MainDb::ParticipantState> MainDb::getChatMessageParticipantsThatHaveDisplayed (
const shared_ptr<EventLog> &eventLog
) const {
return L_DB_TRANSACTION {
L_D();
const EventLogPrivate *dEventLog = eventLog->getPrivate();
MainDbKeyPrivate *dEventKey = static_cast<MainDbKey &>(dEventLog->dbKey).getPrivate();
const long long &eventId = dEventKey->storageId;
int stateInt = static_cast<int>(ChatMessage::State::Displayed);
unsigned int state;
soci::statement statement = (
d->dbSession.getBackendSession()->prepare << "SELECT state FROM chat_message_participant WHERE event_id = :eventId",
soci::into(state), soci::use(eventId)
static const string query = "SELECT sip_address.value, chat_message_participant.state_change_time"
" FROM sip_address, chat_message_participant"
" WHERE event_id = :eventId AND state = :state"
" AND sip_address.id = chat_message_participant.participant_sip_address_id";
soci::rowset<soci::row> rows = (d->dbSession.getBackendSession()->prepare << query,
soci::use(eventId), soci::use(stateInt)
);
statement.execute();
list<ChatMessage::State> states;
while (statement.fetch())
states.push_back(ChatMessage::State(state));
return states;
list<MainDb::ParticipantState> result;
for (const auto &row : rows)
result.emplace_back(IdentityAddress(row.get<string>(0)), ChatMessage::State::Displayed, Utils::getTmAsTimeT(row.get<tm>(1)));
return result;