...
 
Commits (6)
......@@ -2564,6 +2564,8 @@ LinphoneStatus linphone_core_start (LinphoneCore *lc) {
} else {
linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL);
}
L_GET_PRIVATE_FROM_C_OBJECT(lc)->startMessageKillers();
return 0;
} catch (const CorePrivate::DatabaseConnectionFailure &e) {
......
......@@ -320,6 +320,8 @@ void _linphone_chat_room_notify_security_event(LinphoneChatRoom *cr, const Linph
void _linphone_chat_room_notify_subject_changed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_conference_joined(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_conference_left(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_message_killer_started(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_message_killer_finished(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_undecryptable_message_received(LinphoneChatRoom *cr, LinphoneChatMessage *msg);
void _linphone_chat_room_notify_chat_message_received(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
void _linphone_chat_room_notify_chat_message_sent(LinphoneChatRoom *cr, const LinphoneEventLog *event_log);
......@@ -336,6 +338,8 @@ void _linphone_chat_message_notify_participant_imdn_state_changed(LinphoneChatMe
void _linphone_chat_message_notify_file_transfer_recv(LinphoneChatMessage *msg, const LinphoneContent* content, const LinphoneBuffer *buffer);
void _linphone_chat_message_notify_file_transfer_send(LinphoneChatMessage *msg, const LinphoneContent* content, size_t offset, size_t size);
void _linphone_chat_message_notify_file_transfer_progress_indication(LinphoneChatMessage *msg, const LinphoneContent* content, size_t offset, size_t total);
void _linphone_chat_message_notify_message_killer_started(LinphoneChatMessage* msg);
void _linphone_chat_message_notify_message_killer_finished(LinphoneChatMessage* msg);
void _linphone_chat_message_clear_callbacks (LinphoneChatMessage *msg);
......
......@@ -169,6 +169,18 @@ typedef LinphoneBuffer * (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneCha
*/
typedef void (*LinphoneChatMessageCbsFileTransferProgressIndicationCb)(LinphoneChatMessage *msg, const LinphoneContent* content, size_t offset, size_t total);
/**
* Call back used to notify message killer started
* @param msg #LinphoneChatMessage object
*/
typedef void (*LinphoneChatMessageCbsMessageKillerStartedCb)(LinphoneChatMessage* msg);
/**
* Call back used to notify message killer finished
* @param msg #LinphoneChatMessage object
*/
typedef void (*LinphoneChatMessageCbsMessageKillerFinishedCb)(LinphoneChatMessage* msg);
/**
* Is composing notification callback prototype.
* @param[in] cr #LinphoneChatRoom involved in the conversation
......@@ -275,6 +287,20 @@ typedef void (*LinphoneChatRoomCbsConferenceJoinedCb) (LinphoneChatRoom *cr, con
*/
typedef void (*LinphoneChatRoomCbsConferenceLeftCb) (LinphoneChatRoom *cr, const LinphoneEventLog *eventLog);
/**
* Callback used to notify a chat room that a message killer has been started.
* @param[in] cr #LinphoneChatRoom object
* @param[in] event_log #LinphoneEventLog The event to be notified
*/
typedef void (*LinphoneChatRoomCbsMessageKillerStartedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *eventLog);
/**
* Callback used to notify a chat room that a message killer has been finished.
* @param[in] cr #LinphoneChatRoom object
* @param[in] event_log #LinphoneEventLog The event to be notified
*/
typedef void (*LinphoneChatRoomCbsMessageKillerFinishedCb) (LinphoneChatRoom *cr, const LinphoneEventLog *eventLog);
/**
* Callback used when a group chat room is created server-side to generate the address of the chat room.
* The function linphone_chat_room_set_conference_address() needs to be called by this callback.
......
......@@ -133,6 +133,34 @@ LINPHONE_PUBLIC LinphoneChatMessageCbsParticipantImdnStateChangedCb linphone_cha
*/
LINPHONE_PUBLIC void linphone_chat_message_cbs_set_participant_imdn_state_changed (LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsParticipantImdnStateChangedCb cb);
/**
* Get the message killer started callback.
* @param[in] cbs #LinphoneChatMessageCbs object.
* @return The current message killer started callback.
*/
LINPHONE_PUBLIC LinphoneChatMessageCbsMessageKillerStartedCb linphone_chat_message_cbs_get_message_killer_started (const LinphoneChatMessageCbs *cbs);
/**
* Set the message killer started callback.
* @param[in] cbs LinphoneChatMessageCbs object.
* @param[in] cb The message killer started callback to be used.
*/
LINPHONE_PUBLIC void linphone_chat_message_cbs_set_message_killer_started (LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsMessageKillerStartedCb cb);
/**
* Get the message killer finished callback.
* @param[in] cbs #LinphoneChatMessageCbs object.
* @return The current message killer finished callback.
*/
LINPHONE_PUBLIC LinphoneChatMessageCbsMessageKillerFinishedCb linphone_chat_message_cbs_get_message_killer_finished (const LinphoneChatMessageCbs *cbs);
/**
* Set the message killer finished callback.
* @param[in] cbs LinphoneChatMessageCbs object.
* @param[in] cb The message killer finished callback to be used.
*/
LINPHONE_PUBLIC void linphone_chat_message_cbs_set_message_killer_finished (LinphoneChatMessageCbs *cbs, LinphoneChatMessageCbsMessageKillerFinishedCb cb);
/**
* @}
*/
......
......@@ -361,6 +361,33 @@ LINPHONE_PUBLIC bool_t linphone_chat_message_is_forward (LinphoneChatMessage *ms
*/
LINPHONE_PUBLIC const char *linphone_chat_message_get_forward_info (const LinphoneChatMessage *msg);
/**
* Returns true if the chat message is an ephemeral message.
* @param[in] msg #LinphoneChatMessage object.
* @return true if it is an ephemeral message, false otherwise
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_ephemeral(LinphoneChatMessage *msg);
/**
* Returns lifetime of an ephemeral message.
* @param[in] msg #LinphoneChatMessage object.
* @return the lifetime of an ephemeral message, by default 86400s.
*/
LINPHONE_PUBLIC double linphone_chat_message_get_ephemeral_time (LinphoneChatMessage *msg);
/**
* Returns the time at which an ephemeral message is read and its lifetime will be counted.
* @param[in] msg #LinphoneChatMessage object.
* @return the time at which an ephemeral message is read. By default 0, means the message has not been read.
*/
LINPHONE_PUBLIC time_t linphone_chat_message_get_ephemeral_start_time (LinphoneChatMessage *msg);
/**
* Configure the message killer to receive notifications of ephemeral message. To add after #linphone_chat_message_cbs_set_message_killer_started and #linphone_chat_message_cbs_set_message_killer_finished.
* @param[in] msg #LinphoneChatMessage object.
*/
LINPHONE_PUBLIC void linphone_chat_message_configure_message_killer (LinphoneChatMessage *msg);
/**
* Fulfill a chat message char by char. Message linked to a Real Time Text Call send char in realtime following RFC 4103/T.140
* To commit a message, use #linphone_chat_room_send_message
......
......@@ -271,6 +271,34 @@ LINPHONE_PUBLIC LinphoneChatRoomCbsConferenceLeftCb linphone_chat_room_cbs_get_c
*/
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_conference_left (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsConferenceLeftCb cb);
/**
* Get the message killer started callback.
* @param[in] cbs LinphoneChatRoomCbs object.
* @return The current message killer started callback.
*/
LINPHONE_PUBLIC LinphoneChatRoomCbsMessageKillerStartedCb linphone_chat_room_cbs_get_message_killer_started (const LinphoneChatRoomCbs *cbs);
/**
* Set the message killer started callback.
* @param[in] cbs LinphoneChatRoomCbs object.
* @param[in] cb The message killer started callback to be used.
*/
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_message_killer_started (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsMessageKillerStartedCb cb);
/**
* Get the message killer finished callback.
* @param[in] cbs LinphoneChatRoomCbs object.
* @return The current message killer finished callback.
*/
LINPHONE_PUBLIC LinphoneChatRoomCbsMessageKillerFinishedCb linphone_chat_room_cbs_get_message_killer_finished (const LinphoneChatRoomCbs *cbs);
/**
* Set the message killer finished callback.
* @param[in] cbs LinphoneChatRoomCbs object.
* @param[in] cb The message killer finished callback to be used.
*/
LINPHONE_PUBLIC void linphone_chat_room_cbs_set_message_killer_finished (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsMessageKillerFinishedCb cb);
/**
* Get the conference address generation callback.
* @param[in] cbs #LinphoneChatRoomCbs object
......
......@@ -156,6 +156,20 @@ LINPHONE_PUBLIC void linphone_chat_room_receive_chat_message (LinphoneChatRoom *
*/
LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr);
/**
* Enable or disable the ephemeral message feature in the chat room.
* @param[in] cr #LinphoneChatRoom object
* @param[in] ephem TRUE if the message should be ephemeral, FALSE otherwise.
*/
LINPHONE_PUBLIC void linphone_chat_room_enable_ephemeral (LinphoneChatRoom *cr, bool_t ephem);
/**
* Set lifetime of ephemral message to the chat room. After the time elapsed since the message was read, the message will be deleted.
* @param[in] cr #LinphoneChatRoom object
* @param[in] time The ephemral time, default 24h, 86400s
*/
LINPHONE_PUBLIC void linphone_chat_room_set_ephemeral_time (LinphoneChatRoom *cr, double time);
/**
* Delete a message from the chat room history.
* @param[in] cr The #LinphoneChatRoom object corresponding to the conversation.
......
......@@ -115,6 +115,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
chat/chat-message/is-composing-message.h
chat/chat-message/notification-message-p.h
chat/chat-message/notification-message.h
chat/chat-message/chat-message-killer.h
chat/chat-room/chat-room-params.h
chat/chat-room/abstract-chat-room-p.h
chat/chat-room/abstract-chat-room.h
......@@ -300,6 +301,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
chat/chat-message/imdn-message.cpp
chat/chat-message/is-composing-message.cpp
chat/chat-message/notification-message.cpp
chat/chat-message/chat-message-killer.cpp
chat/chat-room/abstract-chat-room.cpp
chat/chat-room/basic-chat-room.cpp
chat/chat-room/chat-room.cpp
......
......@@ -31,6 +31,8 @@ struct _LinphoneChatMessageCbs {
LinphoneChatMessageCbsFileTransferSendCb file_transfer_send;
LinphoneChatMessageCbsFileTransferProgressIndicationCb file_transfer_progress_indication;
LinphoneChatMessageCbsParticipantImdnStateChangedCb participant_imdn_state_changed;
LinphoneChatMessageCbsMessageKillerStartedCb message_killer_started;
LinphoneChatMessageCbsMessageKillerFinishedCb message_killer_finished;
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatMessageCbs);
......@@ -131,3 +133,29 @@ void linphone_chat_message_cbs_set_participant_imdn_state_changed (
) {
cbs->participant_imdn_state_changed = cb;
}
LinphoneChatMessageCbsMessageKillerStartedCb linphone_chat_message_cbs_get_message_killer_started (
const LinphoneChatMessageCbs *cbs
) {
return cbs->message_killer_started;
}
void linphone_chat_message_cbs_set_message_killer_started (
LinphoneChatMessageCbs *cbs,
LinphoneChatMessageCbsMessageKillerStartedCb cb
) {
cbs->message_killer_started = cb;
}
LinphoneChatMessageCbsMessageKillerFinishedCb linphone_chat_message_cbs_get_message_killer_finished (
const LinphoneChatMessageCbs *cbs
) {
return cbs->message_killer_finished;
}
void linphone_chat_message_cbs_set_message_killer_finished (
LinphoneChatMessageCbs *cbs,
LinphoneChatMessageCbsMessageKillerFinishedCb cb
) {
cbs->message_killer_finished = cb;
}
......@@ -168,6 +168,14 @@ void _linphone_chat_message_notify_file_transfer_progress_indication(LinphoneCha
NOTIFY_IF_EXIST(FileTransferProgressIndication, file_transfer_progress_indication, msg, content, offset, total)
}
void _linphone_chat_message_notify_message_killer_started(LinphoneChatMessage* msg) {
NOTIFY_IF_EXIST(MessageKillerStarted, message_killer_started, msg)
}
void _linphone_chat_message_notify_message_killer_finished(LinphoneChatMessage* msg) {
NOTIFY_IF_EXIST(MessageKillerFinished, message_killer_finished, msg)
}
// =============================================================================
// Getter and setters
// =============================================================================
......@@ -250,6 +258,23 @@ const char *linphone_chat_message_get_forward_info (const LinphoneChatMessage *m
return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getForwardInfo());
}
bool_t linphone_chat_message_is_ephemeral (LinphoneChatMessage *msg) {
return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isEphemeral();
}
double linphone_chat_message_get_ephemeral_time (LinphoneChatMessage *msg) {
return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getEphemeralTime();
}
time_t linphone_chat_message_get_ephemeral_start_time (LinphoneChatMessage *msg) {
return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getEphemeralStartTime();
}
void linphone_chat_message_configure_message_killer (LinphoneChatMessage *msg) {
if (L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getDirection() == LinphonePrivate::ChatMessage::Direction::Incoming)
L_GET_CPP_PTR_FROM_C_OBJECT(msg)->configureMessageKiller();
}
void linphone_chat_message_add_custom_header(
LinphoneChatMessage *msg,
const char *header_name,
......
......@@ -45,6 +45,8 @@ struct _LinphoneChatRoomCbs {
LinphoneChatRoomCbsParticipantRegistrationSubscriptionRequestedCb participantRegistrationSubscriptionRequestedCb;
LinphoneChatRoomCbsParticipantRegistrationUnsubscriptionRequestedCb participantRegistrationUnsubscriptionRequestedCb;
LinphoneChatRoomCbsShouldChatMessageBeStoredCb shouldMessageBeStoredCb;
LinphoneChatRoomCbsMessageKillerStartedCb messageKillerStartedCb;
LinphoneChatRoomCbsMessageKillerFinishedCb messageKillerFinishedCb;
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneChatRoomCbs);
......@@ -201,6 +203,22 @@ void linphone_chat_room_cbs_set_conference_left (LinphoneChatRoomCbs *cbs, Linph
cbs->conferenceLeftCb = cb;
}
LinphoneChatRoomCbsMessageKillerStartedCb linphone_chat_room_cbs_get_message_killer_started (const LinphoneChatRoomCbs *cbs) {
return cbs->messageKillerStartedCb;
}
void linphone_chat_room_cbs_set_message_killer_started (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsMessageKillerStartedCb cb) {
cbs->messageKillerStartedCb = cb;
}
LinphoneChatRoomCbsMessageKillerFinishedCb linphone_chat_room_cbs_get_message_killer_finished (const LinphoneChatRoomCbs *cbs) {
return cbs->messageKillerFinishedCb;
}
void linphone_chat_room_cbs_set_message_killer_finished (LinphoneChatRoomCbs *cbs, LinphoneChatRoomCbsMessageKillerFinishedCb cb) {
cbs->messageKillerFinishedCb = cb;
}
LinphoneChatRoomCbsConferenceAddressGenerationCb linphone_chat_room_cbs_get_conference_address_generation (const LinphoneChatRoomCbs *cbs) {
return cbs->conferenceAddressGenerationCb;
}
......
......@@ -209,6 +209,14 @@ void linphone_chat_room_mark_as_read (LinphoneChatRoom *cr) {
L_GET_CPP_PTR_FROM_C_OBJECT(cr)->markAsRead();
}
void linphone_chat_room_enable_ephemeral (LinphoneChatRoom *cr, bool_t ephem) {
L_GET_CPP_PTR_FROM_C_OBJECT(cr)->enableEphemeral(ephem);
}
void linphone_chat_room_set_ephemeral_time (LinphoneChatRoom *cr, double time) {
L_GET_CPP_PTR_FROM_C_OBJECT(cr)->setEphemeralTime(time);
}
int linphone_chat_room_get_unread_messages_count (LinphoneChatRoom *cr) {
return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getUnreadChatMessageCount();
}
......@@ -521,6 +529,14 @@ void _linphone_chat_room_notify_conference_left(LinphoneChatRoom *cr, const Linp
NOTIFY_IF_EXIST(ConferenceLeft, conference_left, cr, eventLog)
}
void _linphone_chat_room_notify_message_killer_started(LinphoneChatRoom *cr, const LinphoneEventLog *eventLog) {
NOTIFY_IF_EXIST(MessageKillerStarted, message_killer_started, cr, eventLog)
}
void _linphone_chat_room_notify_message_killer_finished(LinphoneChatRoom *cr, const LinphoneEventLog *eventLog) {
NOTIFY_IF_EXIST(MessageKillerFinished, message_killer_finished, cr, eventLog)
}
void _linphone_chat_room_notify_undecryptable_message_received(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
NOTIFY_IF_EXIST(UndecryptableMessageReceived, undecryptable_message_received, cr, msg)
}
......
/*
* chat-message-killer.cpp
* Copyright (C) 2010-2019 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/utils/general.h"
#include "chat-message-killer.h"
#include "event-log/event-log.h"
#include "db/main-db.h"
#include "db/main-db-p.h"
#include "core/core-p.h"
#include "core/core.h"
#include "db/main-db-key-p.h"
#include "private.h"
#include "c-wrapper/c-wrapper.h"
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// =============================================================================
ChatMessageKiller::ChatMessageKiller (double duration, MainDbEventKey dbKey, const ConferenceId &conferenceId): duration(duration), dbKey(dbKey), conferenceId(conferenceId) {
timer = nullptr;
bgTask.setName("ephemeral message timeout");
start = false;
chatMessage = nullptr;
}
ChatMessageKiller::ChatMessageKiller (MainDbEventKey dbKey, const ConferenceId &conferenceId) : ChatMessageKiller(86400, dbKey, conferenceId) {
}
ChatMessageKiller::~ChatMessageKiller () {
uninitTimer();
chatMessage = nullptr;
}
// -----------------------------------------------------------------------------
int ChatMessageKiller::timerExpired (void *data, unsigned int revents) {
ChatMessageKiller *d = static_cast<ChatMessageKiller *>(data);
// stop timer
d->uninitTimer();
// delete message in database for ephemral messag
shared_ptr<LinphonePrivate::EventLog> event = LinphonePrivate::MainDb::getEventFromKey(d->dbKey);
shared_ptr<AbstractChatRoom> chatRoom = d->dbKey.getPrivate()->core.lock()->findChatRoom(d->conferenceId);
if (chatRoom && event) {
_linphone_chat_room_notify_message_killer_finished(L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(event));
if (d->chatMessage) {
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(L_GET_C_BACK_PTR(d->chatMessage));
if (cbs && linphone_chat_message_cbs_get_message_killer_finished(cbs))
linphone_chat_message_cbs_get_message_killer_finished(cbs)(L_GET_C_BACK_PTR(d->chatMessage));
_linphone_chat_message_notify_message_killer_finished(L_GET_C_BACK_PTR(d->chatMessage));
d->setChatMessage(NULL);
}
}
if (event)
LinphonePrivate::EventLog::deleteFromDatabase(event);
return BELLE_SIP_STOP;
}
void ChatMessageKiller::startTimer () {
auto core = dbKey.getPrivate()->core.lock();
shared_ptr<AbstractChatRoom> chatRoom = core->findChatRoom(conferenceId);
shared_ptr<LinphonePrivate::EventLog> event = LinphonePrivate::MainDb::getEventFromKey(dbKey);
if (chatRoom && event) {
_linphone_chat_room_notify_message_killer_started(L_GET_C_BACK_PTR(chatRoom), L_GET_C_BACK_PTR(event));
if (chatMessage) {
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(L_GET_C_BACK_PTR(chatMessage));
if (cbs && linphone_chat_message_cbs_get_message_killer_started(cbs))
linphone_chat_message_cbs_get_message_killer_started(cbs)(L_GET_C_BACK_PTR(chatMessage));
_linphone_chat_message_notify_message_killer_started(L_GET_C_BACK_PTR(chatMessage));
}
}
if (!timer)
timer = core->getCCore()->sal->createTimer(timerExpired, this, (unsigned int)duration*1000, "ephemeral message timeout");
else
belle_sip_source_set_timeout(timer, (unsigned int)duration*1000);
bgTask.start(core, 1);
}
void ChatMessageKiller::setDuration(double time) {
duration = time;
}
void ChatMessageKiller::setChatMessage (const shared_ptr<ChatMessage> &message) {
chatMessage = message;
}
void ChatMessageKiller::setStart() {
start = TRUE;
}
bool_t ChatMessageKiller::getStart() {
return start;
}
void ChatMessageKiller::uninitTimer() {
if (timer) {
auto core = dbKey.getPrivate()->core.lock()->getCCore();
if (core && core->sal)
core->sal->cancelTimer(timer);
belle_sip_object_unref(timer);
timer = nullptr;
}
bgTask.stop();
}
LINPHONE_END_NAMESPACE
/*
* chat-message-killer.h
* Copyright (C) 2010-2019 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_CHAT_MESSAGE_KILLER_H_
#define _L_CHAT_MESSAGE_KILLER_H_
#include <belle-sip/types.h>
#include <map>
#include "utils/background-task.h"
#include "core/core-accessor.h"
#include "db/main-db-event-key.h"
#include "conference/conference-id.h"
#include "chat-message.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ChatMessageKiller {
friend class MainDb;
friend class MainDbEventKey;
public:
explicit ChatMessageKiller (MainDbEventKey dbKey, const ConferenceId &conferenceId);
explicit ChatMessageKiller (double duration, MainDbEventKey dbKey, const ConferenceId &conferenceId);
~ChatMessageKiller ();
static int timerExpired (void *data, unsigned int revents);
void startTimer ();
void setDuration (double time);
void setChatMessage(const std::shared_ptr<ChatMessage> &message);
void uninitTimer ();
void setStart ();
bool_t getStart ();
private:
belle_sip_source_t *timer;
BackgroundTask bgTask;
double duration;
MainDbEventKey dbKey;
ConferenceId conferenceId;
std::shared_ptr<ChatMessage> chatMessage;
bool_t start;
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_CHAT_MESSAGE_KILLER_H_
......@@ -83,6 +83,10 @@ public:
void setForwardInfo (const std::string &fInfo);
void enableEphemeralWithTime (double time);
void setEphemeralStartTime (time_t startTime);
void setAuthenticatedFromAddress (const IdentityAddress &authenticatedFromAddress) {
this->authenticatedFromAddress = authenticatedFromAddress;
}
......@@ -255,6 +259,10 @@ private:
ChatMessage::Direction direction = ChatMessage::Direction::Incoming;
std::string forwardInfo;
bool isEphemeral = false;
double ephemeralTime = 86400; // 24h
time_t ephemeralStartTime = 0;
std::list<Content *> contents;
bool encryptionPrevented = false;
......
......@@ -46,6 +46,8 @@
#include "ortp/b64.h"
#include "db/main-db-key-p.h"
//#include "db/main-db-p.h"
// =============================================================================
using namespace std;
......@@ -205,8 +207,19 @@ void ChatMessagePrivate::setState (ChatMessage::State newState) {
// Wait until all files are downloaded before sending displayed IMDN
static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDisplayNotification(q->getSharedFromThis());
}
// 6. update in database for ephemeral message if necessary.
if (isEphemeral && (state == ChatMessage::State::Displayed)) {
// set ephemeral start time
ephemeralStartTime = ::ms_time(NULL);
q->getChatRoom()->getCore()->getPrivate()->mainDb->setChatMessagesEphemeralStartTime(dbKey.getStorageId(), ephemeralStartTime);
// start chat message killer for this message
shared_ptr<ChatMessageKiller> killer = q->getChatRoom()->getCore()->getPrivate()->getMessageKiller(q->getSharedFromThis());
killer->startTimer();
}
// 6. Update in database if necessary.
// 7. Update in database if necessary.
if (state != ChatMessage::State::InProgress && state != ChatMessage::State::FileTransferError && state != ChatMessage::State::FileTransferInProgress) {
updateInDb();
}
......@@ -317,6 +330,10 @@ void ChatMessagePrivate::setFileTransferFilepath (const string &path) {
fileTransferFilePath = path;
}
void ChatMessagePrivate::setEphemeralStartTime (time_t startTime) {
ephemeralStartTime = startTime;
}
const string &ChatMessagePrivate::getAppdata () const {
for (const Content *c : getContents()) {
if (!c->getAppData("legacy").empty()) {
......@@ -1088,6 +1105,11 @@ void ChatMessagePrivate::setForwardInfo (const string &fInfo) {
forwardInfo = fInfo;
}
void ChatMessagePrivate::enableEphemeralWithTime (double time) {
isEphemeral = TRUE;
ephemeralTime = time;
}
void ChatMessagePrivate::loadContentsFromDatabase () const {
L_Q();
......@@ -1102,6 +1124,12 @@ void ChatMessagePrivate::loadContentsFromDatabase () const {
}
}
long long ChatMessage::getStorageId () const {
L_D();
return d->dbKey.getStorageId();
}
bool ChatMessage::isRead () const {
L_D();
......@@ -1143,6 +1171,25 @@ bool ChatMessage::getToBeStored () const {
return d->toBeStored;
}
bool ChatMessage::isEphemeral () const {
L_D();
return d->isEphemeral;
}
double ChatMessage::getEphemeralTime () const {
L_D();
return d->ephemeralTime;
}
time_t ChatMessage::getEphemeralStartTime () const {
L_D();
return d->ephemeralStartTime;
}
void ChatMessage::configureMessageKiller() {
getChatRoom()->getCore()->getPrivate()->getMessageKiller(getSharedFromThis());
}
void ChatMessage::setToBeStored (bool value) {
L_D();
d->toBeStored = value;
......@@ -1252,6 +1299,8 @@ void ChatMessage::send () {
d->loadContentsFromDatabase();
getChatRoom()->getPrivate()->sendChatMessage(getSharedFromThis());
if (isEphemeral())
configureMessageKiller();
}
bool ChatMessage::downloadFile(FileTransferContent *fileTransferContent) {
......
......@@ -89,6 +89,12 @@ public:
const IdentityAddress &getToAddress () const;
const std::string &getForwardInfo () const;
bool isEphemeral () const;
double getEphemeralTime () const;
time_t getEphemeralStartTime () const;
void configureMessageKiller();
// TODO: Return a cpp reference.
const LinphoneErrorInfo *getErrorInfo () const;
......@@ -115,6 +121,8 @@ public:
bool downloadFile (FileTransferContent *content);
bool isFileTransferInProgress () const;
long long getStorageId () const;
protected:
explicit ChatMessage (ChatMessagePrivate &p);
......
......@@ -102,6 +102,8 @@ public:
) const = 0;
virtual void markAsRead () = 0;
virtual void enableEphemeral (bool ephem) = 0;
virtual void setEphemeralTime (double time) = 0;
virtual const std::shared_ptr<ChatRoomParams> &getCurrentParams() const = 0;
......
......@@ -116,6 +116,8 @@ private:
std::unique_ptr<IsComposing> isComposingHandler;
bool isComposing = false;
bool isEphemeral = false;
double ephemeralTime = 86400; //24 hours = 86400s
L_DECLARE_PUBLIC(ChatRoom);
};
......
......@@ -134,7 +134,11 @@ void ChatRoomPrivate::removeTransientChatMessage (const shared_ptr<ChatMessage>
shared_ptr<ChatMessage> ChatRoomPrivate::createChatMessage (ChatMessage::Direction direction) {
L_Q();
return shared_ptr<ChatMessage>(new ChatMessage(q->getSharedFromThis(), direction));
shared_ptr<ChatMessage> message = shared_ptr<ChatMessage>(new ChatMessage(q->getSharedFromThis(), direction));
if (isEphemeral && capabilities & ChatRoom::Capabilities::Encrypted) {
message->getPrivate()->enableEphemeralWithTime(ephemeralTime);
}
return message;
}
shared_ptr<ImdnMessage> ChatRoomPrivate::createImdnMessage (
......@@ -574,4 +578,14 @@ const std::shared_ptr<ChatRoomParams> &ChatRoom::getCurrentParams() const {
return d->params;
}
void ChatRoom::enableEphemeral (bool ephem) {
L_D();
d->isEphemeral = ephem;
}
void ChatRoom::setEphemeralTime (double time) {
L_D();
d->ephemeralTime = time;
}
LINPHONE_END_NAMESPACE
......@@ -82,6 +82,8 @@ public:
) const override;
void markAsRead () override;
void enableEphemeral (bool ephem) override;
void setEphemeralTime (double time) override;
const std::shared_ptr<ChatRoomParams> &getCurrentParams() const override;
......
......@@ -213,6 +213,16 @@ void ProxyChatRoom::markAsRead () {
d->chatRoom->markAsRead();
}
void ProxyChatRoom::enableEphemeral (bool ephem) {
L_D();
d->chatRoom->enableEphemeral(ephem);
}
void ProxyChatRoom::setEphemeralTime (double time) {
L_D();
d->chatRoom->setEphemeralTime(time);
}
// -----------------------------------------------------------------------------
const IdentityAddress &ProxyChatRoom::getConferenceAddress () const {
......
......@@ -77,6 +77,8 @@ public:
) const override;
void markAsRead () override;
void enableEphemeral (bool ephem) override;
void setEphemeralTime (double time) override;
const IdentityAddress &getConferenceAddress () const override;
......
......@@ -52,6 +52,14 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr<Ch
|| message->getPrivate()->getNegativeDeliveryNotificationRequired()
|| message->getPrivate()->getDisplayNotificationRequired()
) {
const string targetNamespace = "ephemeral";
if (message->isEphemeral()) {
double time = message->getEphemeralTime();
const string &buf = Utils::toString(time);
cpimMessage.addMessageHeader(Cpim::NsHeader("urn:xmpp:ephemeral:0", targetNamespace));
cpimMessage.addMessageHeader(Cpim::GenericHeader(targetNamespace + ".time", buf));
}
const string imdnNamespace = "imdn";
cpimMessage.addMessageHeader(Cpim::NsHeader("urn:ietf:params:imdn", imdnNamespace));
......@@ -162,7 +170,9 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr<Ch
message->getPrivate()->setDisplayNotificationRequired(false);
string imdnNamespace = "";
string targetNamespace = "";
auto messageHeaders = cpimMessage->getMessageHeaders();
int namespaceNum = 0;
if (messageHeaders) {
for (const auto &header : *messageHeaders.get()) {
if (header->getName() != "NS")
......@@ -170,6 +180,12 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr<Ch
auto nsHeader = static_pointer_cast<const Cpim::NsHeader>(header);
if (nsHeader->getUri() == "urn:ietf:params:imdn") {
imdnNamespace = nsHeader->getPrefixName();
namespaceNum ++;
} else if (nsHeader->getUri() == "urn:xmpp:ephemeral:0") {
targetNamespace = nsHeader->getPrefixName();
namespaceNum ++;
}
if (namespaceNum > 1) {
break;
}
}
......@@ -207,6 +223,13 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr<Ch
message->getPrivate()->setForwardInfo(forwardInfoHeader->getValue());
}
}
if (!targetNamespace.empty()) {
auto timeHeader = cpimMessage->getMessageHeader("time", targetNamespace);
double time = Utils::stod(timeHeader->getValue());
message->getPrivate()->enableEphemeralWithTime(time);
}
if (messageIdHeader)
message->getPrivate()->setImdnMessageId(messageIdHeader->getValue());
......
......@@ -348,6 +348,15 @@ void CorePrivate::loadChatRooms () {
sendDeliveryNotifications();
}
void CorePrivate::startMessageKillers () {
for (auto it=messageKillers.begin(); it!=messageKillers.end(); ++it) {
shared_ptr<ChatMessageKiller> killer = it->second;
if (killer->getStart()) {
killer->startTimer();
}
}
}
void CorePrivate::sendDeliveryNotifications () {
L_Q();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCCore());
......
......@@ -27,6 +27,7 @@
#include "db/main-db.h"
#include "object/object-p.h"
#include "sal/call-op.h"
#include "chat/chat-message/chat-message-killer.h"
// =============================================================================
......@@ -74,6 +75,8 @@ public:
void setPlaybackGainDb (AudioStream *stream, float gain);
void loadChatRooms ();
void startMessageKillers ();
void startKillerWithMessage(MainDbEventKey key, double duration);
void sendDeliveryNotifications ();
void insertChatRoom (const std::shared_ptr<AbstractChatRoom> &chatRoom);
void insertChatRoomWithDb (const std::shared_ptr<AbstractChatRoom> &chatRoom, unsigned int notifyId = 0);
......@@ -118,6 +121,8 @@ public:
belle_sip_main_loop_t *getMainLoop();
bool basicToFlexisipChatroomMigrationEnabled()const;
std::unique_ptr<MainDb> mainDb;
std::unordered_map<MainDbEventKey, std::shared_ptr<ChatMessageKiller>> messageKillers;
std::shared_ptr<ChatMessageKiller> getMessageKiller(std::shared_ptr<ChatMessage> message);
#ifdef HAVE_ADVANCED_IM
std::unique_ptr<RemoteConferenceListEventHandler> remoteListEventHandler;
std::unique_ptr<LocalConferenceListEventHandler> localListEventHandler;
......
......@@ -96,6 +96,9 @@ void CorePrivate::init () {
}
loadChatRooms();
// load messageKillers
if (mainDb->isInitialized())
messageKillers = mainDb->getEphemeralMessageKillers();
} else lWarning() << "Database explicitely not requested, this Core is built with no database support.";
}
......@@ -118,6 +121,7 @@ void CorePrivate::uninit () {
ms_usleep(10000);
}
messageKillers.clear();
chatRoomsById.clear();
noCreatedClientGroupChatRooms.clear();
listeners.clear();
......@@ -216,6 +220,24 @@ bool CorePrivate::basicToFlexisipChatroomMigrationEnabled()const{
return linphone_config_get_bool(linphone_core_get_config(q->getCCore()), "misc", "enable_basic_to_client_group_chat_room_migration", FALSE);
}
shared_ptr<ChatMessageKiller> CorePrivate::getMessageKiller(shared_ptr<ChatMessage> message) {
MainDbEventKey key = MainDbEventKey(message->getCore(), message->getStorageId());
auto it = messageKillers.find(key);
if (it == messageKillers.end()) {
shared_ptr<ChatMessageKiller> killer (new ChatMessageKiller(message->getEphemeralTime(), key, message->getChatRoom()->getConferenceId()));
killer->setChatMessage(message);
messageKillers[key] = killer;
return killer;
} else {
shared_ptr<ChatMessageKiller> killer = it->second;
LinphoneChatMessageCbs *cbs = linphone_chat_message_get_callbacks(L_GET_C_BACK_PTR(message));
if (cbs && linphone_chat_message_cbs_get_message_killer_started(cbs)) {
killer->setChatMessage(message);
messageKillers[key] = killer;
}
return it->second;
}
}
// =============================================================================
......
......@@ -64,6 +64,7 @@ class LINPHONE_PUBLIC Core : public Object {
friend class RemoteConferenceListEventHandler;
friend class ServerGroupChatRoom;
friend class ServerGroupChatRoomPrivate;
friend class ChatMessageKiller;
public:
L_OVERRIDE_SHARED_FROM_THIS(Core);
......
......@@ -87,7 +87,7 @@ namespace Statements {
)",
/* SelectConferenceEvent */ R"(
SELECT conference_event_view.id AS event_id, type, conference_event_view.creation_time, from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address.value, participant_sip_address.value, conference_event_view.subject, delivery_notification_required, display_notification_required, peer_sip_address.value, local_sip_address.value, marked_as_read, forward_info
SELECT conference_event_view.id AS event_id, type, conference_event_view.creation_time, from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address.value, participant_sip_address.value, conference_event_view.subject, delivery_notification_required, display_notification_required, peer_sip_address.value, local_sip_address.value, marked_as_read, forward_info, ephemeral_time, start_time
FROM conference_event_view
JOIN chat_room ON chat_room.id = chat_room_id
JOIN sip_address AS peer_sip_address ON peer_sip_address.id = peer_sip_address_id
......@@ -100,7 +100,7 @@ namespace Statements {
)",
/* SelectConferenceEvents */ R"(
SELECT conference_event_view.id AS event_id, type, creation_time, from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address.value, participant_sip_address.value, subject, delivery_notification_required, display_notification_required, security_alert, faulty_device, marked_as_read, forward_info
SELECT conference_event_view.id AS event_id, type, creation_time, from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address.value, participant_sip_address.value, subject, delivery_notification_required, display_notification_required, security_alert, faulty_device, marked_as_read, forward_info, ephemeral_time, start_time
FROM conference_event_view
LEFT JOIN sip_address AS from_sip_address ON from_sip_address.id = from_sip_address_id
LEFT JOIN sip_address AS to_sip_address ON to_sip_address.id = to_sip_address_id
......
......@@ -27,6 +27,7 @@
LINPHONE_BEGIN_NAMESPACE
class MainDbChatMessageKey : public MainDbKey {
friend class ChatMessagePrivate;
public:
MainDbChatMessageKey ();
MainDbChatMessageKey (const std::shared_ptr<Core> &core, long long storageId);
......
......@@ -41,4 +41,25 @@ MainDbEventKey::~MainDbEventKey () {
d->core.lock()->getPrivate()->mainDb->getPrivate()->storageIdToEvent.erase(d->storageId);
}
bool MainDbEventKey::operator== (const MainDbEventKey &other) const {
L_D();
const MainDbKeyPrivate *dKey = other.getPrivate();
return dKey->storageId == d->storageId;
}
bool MainDbEventKey::operator!= (const MainDbEventKey &other) const {
return !(*this == other);
}
bool MainDbEventKey::operator< (const MainDbEventKey &other) const {
L_D();
const MainDbKeyPrivate *dKey = other.getPrivate();
return d->storageId < dKey->storageId;
}
const long long &MainDbEventKey::getStorageId () const {
L_D();
return d->storageId;
}
LINPHONE_END_NAMESPACE
......@@ -21,12 +21,14 @@
#define _L_MAIN_DB_EVENT_KEY_H_
#include "main-db-key.h"
#include "main-db-key-p.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class MainDbEventKey : public MainDbKey {
friend class ChatMessageKiller;
public:
MainDbEventKey ();
MainDbEventKey (const std::shared_ptr<Core> &core, long long storageId);
......@@ -35,6 +37,12 @@ public:
MainDbEventKey* clone () const override {
return new MainDbEventKey(*this);
}
bool operator== (const MainDbEventKey &other) const;
bool operator!= (const MainDbEventKey &other) const;
bool operator< (const MainDbEventKey &other) const;
const long long &getStorageId () const;
private:
L_DECLARE_PRIVATE(MainDbKey);
......@@ -42,4 +50,14 @@ private:
LINPHONE_END_NAMESPACE
// Add map key support.
namespace std {
template<>
struct hash<LinphonePrivate::MainDbEventKey> {
std::size_t operator() (const LinphonePrivate::MainDbEventKey &mainDbEventKey) const {
return hash<long long>()(mainDbEventKey.getStorageId());
}
};
}
#endif // ifndef _L_MAIN_DB_EVENT_KEY_H_
......@@ -64,4 +64,9 @@ bool MainDbKey::isValid () const {
return !d->core.expired() && d->storageId >= 0;
}
long long MainDbKey::getStorageId() const {
L_D();
return d->storageId;
}
LINPHONE_END_NAMESPACE
......@@ -42,6 +42,7 @@ public:
MainDbKey &operator= (const MainDbKey &other);
bool isValid () const;
long long getStorageId () const;
private:
L_DECLARE_PRIVATE(MainDbKey);
......
......@@ -41,6 +41,8 @@
#endif
#include "internal/statements.h"
#include "c-wrapper/c-wrapper.h"
// =============================================================================
// See: http://soci.sourceforge.net/doc/3.2/exchange.html
......@@ -54,7 +56,7 @@ LINPHONE_BEGIN_NAMESPACE
#ifdef HAVE_DB_STORAGE
namespace {
constexpr unsigned int ModuleVersionEvents = makeVersion(1, 0, 9);
constexpr unsigned int ModuleVersionEvents = makeVersion(1, 0, 10);
constexpr unsigned int ModuleVersionFriends = makeVersion(1, 0, 0);
constexpr unsigned int ModuleVersionLegacyFriendsImport = makeVersion(1, 0, 0);
constexpr unsigned int ModuleVersionLegacyHistoryImport = makeVersion(1, 0, 0);
......@@ -748,6 +750,11 @@ shared_ptr<EventLog> MainDbPrivate::selectConferenceChatMessageEvent (
}
dChatMessage->setForwardInfo(row.get<string>(19));
if (row.get_indicator(20) != soci::i_null) {
dChatMessage->enableEphemeralWithTime(row.get<double>(20));
dChatMessage->setEphemeralStartTime(dbSession.getTime(row, 21));
}
cache(chatMessage, eventId);
}
......@@ -889,6 +896,7 @@ long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptr<Even
const int &deliveryNotificationRequired = chatMessage->getPrivate()->getPositiveDeliveryNotificationRequired();
const int &displayNotificationRequired = chatMessage->getPrivate()->getDisplayNotificationRequired();
const int &markedAsRead = chatMessage->getPrivate()->isMarkedAsRead() ? 1 : 0;
const bool &isEphemeral = chatMessage->isEphemeral();
*dbSession.getBackendSession() << "INSERT INTO conference_chat_message_event ("
" event_id, from_sip_address_id, to_sip_address_id,"
......@@ -905,6 +913,16 @@ long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptr<Even
soci::use(imdnMessageId), soci::use(isSecured),
soci::use(deliveryNotificationRequired), soci::use(displayNotificationRequired),
soci::use(markedAsRead), soci::use(forwardInfo);
if (isEphemeral) {
const double &ephemeralTime = chatMessage->getEphemeralTime();
const tm &startTime = Utils::getTimeTAsTm(chatMessage->getEphemeralStartTime());
*dbSession.getBackendSession() << "INSERT INTO chat_message_ephemeral_event ("
" event_id, ephemeral_time, start_time"
") VALUES ("
" :eventId, :time, :startTime"
")", soci::use(eventId), soci::use(ephemeralTime), soci::use(startTime);
}
for (const Content *content : chatMessage->getContents())
insertContent(eventId, *content);
......@@ -1391,6 +1409,21 @@ void MainDbPrivate::updateSchema () {
" LEFT JOIN conference_subject_event ON conference_subject_event.event_id = event.id"
" LEFT JOIN conference_security_event ON conference_security_event.event_id = event.id";
}
if (version < makeVersion(1, 0, 10)) {
*session << "DROP VIEW IF EXISTS conference_event_view";
*session << "CREATE VIEW conference_event_view AS"
" SELECT id, type, creation_time, chat_room_id, from_sip_address_id, to_sip_address_id, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address_id, participant_sip_address_id, subject, delivery_notification_required, display_notification_required, security_alert, faulty_device, marked_as_read, forward_info, ephemeral_time, start_time"
" FROM event"
" LEFT JOIN conference_event ON conference_event.event_id = event.id"
" LEFT JOIN conference_chat_message_event ON conference_chat_message_event.event_id = event.id"
" LEFT JOIN conference_notified_event ON conference_notified_event.event_id = event.id"
" LEFT JOIN conference_participant_device_event ON conference_participant_device_event.event_id = event.id"
" LEFT JOIN conference_participant_event ON conference_participant_event.event_id = event.id"
" LEFT JOIN conference_subject_event ON conference_subject_event.event_id = event.id"
" LEFT JOIN conference_security_event ON conference_security_event.event_id = event.id"
" LEFT JOIN chat_message_ephemeral_event ON chat_message_ephemeral_event.event_id = event.id";
}
#endif
}
......@@ -2006,6 +2039,17 @@ void MainDb::init () {
" name" + varcharPrimaryKeyStr(255) + ","
" version INT UNSIGNED NOT NULL"
") " + charset;
*session <<
"CREATE TABLE IF NOT EXISTS chat_message_ephemeral_event ("
" event_id" + primaryKeyStr("BIGINT UNSIGNED") + ","
" ephemeral_time DOUBLE NOT NULL,"
" start_time" + timestampType() + " NOT NULL,"
" FOREIGN KEY (event_id)"
" REFERENCES conference_event(event_id)"
" ON DELETE CASCADE"
") " + charset;
d->updateSchema();
......@@ -2364,6 +2408,21 @@ void MainDb::markChatMessagesAsRead (const ConferenceId &conferenceId) const {
#endif
}
void MainDb::setChatMessagesEphemeralStartTime (const long long &eventId, time_t &time) const {
#ifdef HAVE_DB_STORAGE
static const string query = "UPDATE chat_message_ephemeral_event"
" SET start_time = :startTime"
" WHERE event_id = :eventId";
L_DB_TRANSACTION {
L_D();
const tm &startTime = Utils::getTimeTAsTm(time);
*d->dbSession.getBackendSession() << query, soci::use(startTime),soci::use(eventId);
tr.commit();
};
#endif
}
list<shared_ptr<ChatMessage>> MainDb::getUnreadChatMessages (const ConferenceId &conferenceId) const {
#ifdef HAVE_DB_STORAGE
// TODO: Optimize.
......@@ -2405,6 +2464,44 @@ list<shared_ptr<ChatMessage>> MainDb::getUnreadChatMessages (const ConferenceId
#endif
}
std::unordered_map<MainDbEventKey, std::shared_ptr<ChatMessageKiller>> MainDb::getEphemeralMessageKillers () const {
#ifdef HAVE_DB_STORAGE
return L_DB_TRANSACTION {
L_D();
std::unordered_map<MainDbEventKey, std::shared_ptr<ChatMessageKiller>> messageKillers;
soci::rowset<soci::row> ephemeralMessages = (d->dbSession.getBackendSession()->prepare << "SELECT event_id, ephemeral_time, start_time FROM chat_message_ephemeral_event");
for (const auto &row : ephemeralMessages) {
const long long &eventId = d->dbSession.resolveId(row, 0);
const double &ephemeralTime = row.get<double>(1);
const time_t &startTime = d->dbSession.getTime(row, 2);
soci::row rowf;
*d->dbSession.getBackendSession() << Statements::get(Statements::SelectConferenceEvent),
soci::into(rowf), soci::use(eventId);
ConferenceId conferenceId(IdentityAddress(rowf.get<string>(16)), IdentityAddress(rowf.get<string>(17)));
MainDbEventKey key = MainDbEventKey(getCore(), eventId);
shared_ptr<ChatMessageKiller> killer (new ChatMessageKiller(key, conferenceId));
messageKillers[key] = killer;
if (startTime > 0) {
// startTimer for delete ephemeral messages. If expired, set duration time 0.05s
double duration = difftime(ms_time(0), startTime) > ephemeralTime ? 0.05 : difftime(ms_time(0), startTime);
killer->setDuration(duration);
killer->setStart();
messageKillers[key] = killer;
}
}
return messageKillers;
};
#else
return NULL;
#endif
}
list<MainDb::ParticipantState> MainDb::getChatMessageParticipantsByImdnState (
const shared_ptr<EventLog> &eventLog,
ChatMessage::State state
......@@ -2559,7 +2656,7 @@ list<shared_ptr<ChatMessage>> MainDb::findChatMessages (
list<shared_ptr<ChatMessage>> MainDb::findChatMessagesToBeNotifiedAsDelivered () const {
#ifdef HAVE_DB_STORAGE
static const string query = "SELECT conference_event_view.id AS event_id, type, creation_time, from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address.value, participant_sip_address.value, subject, delivery_notification_required, display_notification_required, security_alert, faulty_device, marked_as_read, chat_room_id, forward_info"
static const string query = "SELECT conference_event_view.id AS event_id, type, creation_time, from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address.value, participant_sip_address.value, subject, delivery_notification_required, display_notification_required, security_alert, faulty_device, marked_as_read, forward_info, ephemeral_time, start_time, chat_room_id"
" FROM conference_event_view"
" LEFT JOIN sip_address AS from_sip_address ON from_sip_address.id = from_sip_address_id"
" LEFT JOIN sip_address AS to_sip_address ON to_sip_address.id = to_sip_address_id"
......@@ -2584,7 +2681,7 @@ list<shared_ptr<ChatMessage>> MainDb::findChatMessagesToBeNotifiedAsDelivered ()
);
for (const auto &row : rows) {
const long long &dbChatRoomId = d->dbSession.resolveId(row, 19);
const long long &dbChatRoomId = d->dbSession.resolveId(row, (int)row.size()-1);
ConferenceId conferenceId = d->getConferenceIdFromCache(dbChatRoomId);
if (!conferenceId.isValid()) {
conferenceId = d->selectConferenceId(dbChatRoomId);
......
......@@ -28,6 +28,8 @@
#include "chat/chat-message/chat-message.h"
#include "conference/conference-id.h"
#include "core/core-accessor.h"
#include "chat/chat-message/chat-message-killer.h"
#include <unordered_map>
// =============================================================================
......@@ -47,6 +49,7 @@ class LINPHONE_INTERNAL_PUBLIC MainDb : public AbstractDb, public CoreAccessor {
friend class MainDbChatMessageKey;
friend class MainDbEventKey;
friend class ChatMessageKiller;
public:
enum Filter {
......@@ -102,6 +105,7 @@ public:
void markChatMessagesAsRead (const ConferenceId &conferenceId) const;
std::list<std::shared_ptr<ChatMessage>> getUnreadChatMessages (const ConferenceId &conferenceId) const;
void setChatMessagesEphemeralStartTime (const long long &eventId, time_t &time) const;
std::list<ParticipantState> getChatMessageParticipantsByImdnState (
const std::shared_ptr<EventLog> &eventLog,
......@@ -118,6 +122,8 @@ public:
ChatMessage::State state,
time_t stateChangeTime
);
std::unordered_map<MainDbEventKey, std::shared_ptr<ChatMessageKiller>> getEphemeralMessageKillers () const;
std::shared_ptr<ChatMessage> getLastChatMessage (const ConferenceId &conferenceId) const;
......
This diff is collapsed.
......@@ -149,6 +149,18 @@ static void chat_room_conference_joined (LinphoneChatRoom *cr, const LinphoneEve
manager->stat.number_of_LinphoneChatRoomConferenceJoined++;
}
static void chat_room_message_killer_started (LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
LinphoneCore *core = linphone_chat_room_get_core(cr);
LinphoneCoreManager *manager = (LinphoneCoreManager *)linphone_core_get_user_data(core);
manager->stat.number_of_LinphoneChatRoomMessageKillerStarted++;
}
static void chat_room_message_killer_finished (LinphoneChatRoom *cr, const LinphoneEventLog *event_log) {
LinphoneCore *core = linphone_chat_room_get_core(cr);
LinphoneCoreManager *manager = (LinphoneCoreManager *)linphone_core_get_user_data(core);
manager->stat.number_of_LinphoneChatRoomMessageKillerFinished++;
}
void core_chat_room_state_changed (LinphoneCore *core, LinphoneChatRoom *cr, LinphoneChatRoomState state) {
if (state == LinphoneChatRoomStateInstantiated) {
LinphoneChatRoomCbs *cbs = linphone_factory_create_chat_room_cbs(linphone_factory_get());
......@@ -163,11 +175,34 @@ void core_chat_room_state_changed (LinphoneCore *core, LinphoneChatRoom *cr, Lin
linphone_chat_room_cbs_set_participant_device_removed(cbs, chat_room_participant_device_removed);
linphone_chat_room_cbs_set_undecryptable_message_received(cbs, undecryptable_message_received);
linphone_chat_room_cbs_set_conference_joined(cbs, chat_room_conference_joined);
linphone_chat_room_cbs_set_message_killer_started(cbs, chat_room_message_killer_started);
linphone_chat_room_cbs_set_message_killer_finished(cbs, chat_room_message_killer_finished);
linphone_chat_room_add_callbacks(cr, cbs);
linphone_chat_room_cbs_unref(cbs);
}
}
void core_global_state_changed (LinphoneCore *lc, LinphoneGlobalState gstate, const char *message) {
if (gstate == LinphoneGlobalConfiguring) {
const bctbx_list_t *chatRooms = linphone_core_get_chat_rooms(lc);
for (const bctbx_list_t *f = chatRooms ; f ; f = bctbx_list_next(f)) {
LinphoneChatRoom *room = (LinphoneChatRoom*)(f->data);
bctbx_list_t *history = linphone_chat_room_get_history(room, 0);
for (bctbx_list_t *item = history; item; item = bctbx_list_next(item)) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)bctbx_list_get_data(item);
if (!!linphone_chat_message_is_ephemeral(msg)) {
LinphoneChatMessageCbs *msgCbs = linphone_chat_message_get_callbacks(msg);
linphone_chat_message_cbs_set_message_killer_started(msgCbs, liblinphone_tester_chat_message_msg_killer_started);
linphone_chat_message_cbs_set_message_killer_finished(msgCbs, liblinphone_tester_chat_message_msg_killer_finished);
linphone_chat_message_add_callbacks(msg, msgCbs);
linphone_chat_message_configure_message_killer(msg);
}
}
bctbx_list_free_with_data(history, (bctbx_list_free_func)linphone_chat_message_unref);
}
}
}
void configure_core_for_conference (LinphoneCore *core, const char* username, const LinphoneAddress *factoryAddr, bool_t server) {
const char *identity = linphone_core_get_identity(core);
const char *new_username;
......@@ -202,14 +237,23 @@ void _start_core(LinphoneCoreManager *lcm) {
linphone_core_manager_start(lcm, TRUE);
}
LinphoneChatMessage *_send_message(LinphoneChatRoom *chatRoom, const char *message) {
LinphoneChatMessage *_send_message_ephemeral(LinphoneChatRoom *chatRoom, const char *message, bool_t isEphemeral) {
LinphoneChatMessage *msg = linphone_chat_room_create_message(chatRoom, message);
LinphoneChatMessageCbs *msgCbs = linphone_chat_message_get_callbacks(msg);
linphone_chat_message_cbs_set_msg_state_changed(msgCbs, liblinphone_tester_chat_message_msg_state_changed);
if (isEphemeral) {
linphone_chat_message_cbs_set_message_killer_started(msgCbs, liblinphone_tester_chat_message_msg_killer_started);
linphone_chat_message_cbs_set_message_killer_finished(msgCbs, liblinphone_tester_chat_message_msg_killer_finished);
linphone_chat_message_configure_message_killer(msg);
}
linphone_chat_message_send(msg);
return msg;
}
LinphoneChatMessage *_send_message(LinphoneChatRoom *chatRoom, const char *message) {
return _send_message_ephemeral(chatRoom, message, FALSE);
}
void _send_file_plus_text(LinphoneChatRoom* cr, const char *sendFilepath, const char *text) {
LinphoneChatMessage *msg;
LinphoneChatMessageCbs *cbs;
......@@ -287,13 +331,15 @@ void _receive_file_plus_text(bctbx_list_t *coresList, LinphoneCoreManager *lcm,
}
// Configure list of core manager for conference and add the listener
bctbx_list_t * init_core_for_conference(bctbx_list_t *coreManagerList) {
bctbx_list_t * init_core_for_conference_ephemeral(bctbx_list_t *coreManagerList, bool_t ephemeralTest) {
LinphoneAddress *factoryAddr = linphone_address_new(sFactoryUri);
bctbx_list_for_each2(coreManagerList, (void (*)(void *, void *))_configure_core_for_conference, (void *) factoryAddr);
linphone_address_unref(factoryAddr);
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
linphone_core_cbs_set_chat_room_state_changed(cbs, core_chat_room_state_changed);
if (ephemeralTest)
linphone_core_cbs_set_global_state_changed(cbs, core_global_state_changed);
bctbx_list_for_each2(coreManagerList, (void (*)(void *, void *))configure_core_for_callbacks, (void *) cbs);
linphone_core_cbs_unref(cbs);
......@@ -304,6 +350,10 @@ bctbx_list_t * init_core_for_conference(bctbx_list_t *coreManagerList) {
return coresList;
}
bctbx_list_t * init_core_for_conference(bctbx_list_t *coreManagerList) {
return init_core_for_conference_ephemeral(coreManagerList, FALSE);
}
void start_core_for_conference(bctbx_list_t *coreManagerList) {
bctbx_list_for_each(coreManagerList, (void (*)(void *))_start_core);
}
......
......@@ -197,6 +197,8 @@ typedef struct _stats {
int number_of_LinphoneMessageFileTransferInProgress;
int number_of_LinphoneMessageDeliveredToUser;
int number_of_LinphoneMessageDisplayed;
int number_of_LinphoneMessageMsgKillerStarted;
int number_of_LinphoneMessageMsgKillerFinished;
int number_of_LinphoneIsComposingActiveReceived;
int number_of_LinphoneIsComposingIdleReceived;
int progress_of_LinphoneFileTransfer;
......@@ -210,6 +212,8 @@ typedef struct _stats {
int number_of_LinphoneChatRoomStateTerminated;
int number_of_LinphoneChatRoomStateTerminationFailed;
int number_of_LinphoneChatRoomStateDeleted;
int number_of_LinphoneChatRoomMessageKillerStarted;
int number_of_LinphoneChatRoomMessageKillerFinished;
int number_of_IframeDecoded;
......@@ -368,6 +372,7 @@ void linphone_core_manager_wait_for_stun_resolution(LinphoneCoreManager *mgr);
void linphone_core_manager_destroy(LinphoneCoreManager* mgr);
void linphone_core_manager_delete_chat_room (LinphoneCoreManager *mgr, LinphoneChatRoom *cr, bctbx_list_t *coresList);
bctbx_list_t * init_core_for_conference(bctbx_list_t *coreManagerList);
bctbx_list_t * init_core_for_conference_ephemeral(bctbx_list_t *coreManagerList, bool_t ephemeralTest);
void start_core_for_conference(bctbx_list_t *coreManagerList);
void reset_counters(stats* counters);
......@@ -380,6 +385,7 @@ void notify_presence_received_for_uri_or_tel(LinphoneCore *lc, LinphoneFriend *l
void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message);
void file_transfer_received(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer);
LinphoneBuffer * tester_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size);
LinphoneChatMessage *_send_message_ephemeral(LinphoneChatRoom *chatRoom, const char *message, bool_t ephemeral);
LinphoneChatMessage *_send_message(LinphoneChatRoom *chatRoom, const char *message);
void _send_file_plus_text(LinphoneChatRoom* cr, const char *sendFilepath, const char *text);
void _send_file(LinphoneChatRoom* cr, const char *sendFilepath);
......@@ -435,6 +441,8 @@ const char *liblinphone_tester_get_subscribe_content(void);
const char *liblinphone_tester_get_notify_content(void);
void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud);
void liblinphone_tester_chat_message_msg_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageState state);
void liblinphone_tester_chat_message_msg_killer_started(LinphoneChatMessage *msg);
void liblinphone_tester_chat_message_msg_killer_finished(LinphoneChatMessage *msg);
void core_chat_room_state_changed (LinphoneCore *core, LinphoneChatRoom *cr, LinphoneChatRoomState state);
void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee);
......
......@@ -1050,6 +1050,13 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState
}
void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* msg) {
LinphoneChatMessageCbs *msgCbs = linphone_chat_message_get_callbacks(msg);
if (linphone_chat_message_is_ephemeral(msg)) {
linphone_chat_message_cbs_set_message_killer_started(msgCbs, liblinphone_tester_chat_message_msg_killer_started);
linphone_chat_message_cbs_set_message_killer_finished(msgCbs, liblinphone_tester_chat_message_msg_killer_finished);
linphone_chat_message_configure_message_killer(msg);
}
char* from=linphone_address_as_string(linphone_chat_message_get_from_address(msg));
stats* counters;
const char *text=linphone_chat_message_get_text(msg);
......@@ -1515,6 +1522,18 @@ void liblinphone_tester_chat_message_msg_state_changed(LinphoneChatMessage *msg,
ms_error("Unexpected state [%s] for msg [%p]",linphone_chat_message_state_to_string(state), msg);
}
void liblinphone_tester_chat_message_msg_killer_started (LinphoneChatMessage *msg) {
LinphoneCore *lc = linphone_chat_message_get_core(msg);
stats *counters = get_stats(lc);
counters->number_of_LinphoneMessageMsgKillerStarted++;
}
void liblinphone_tester_chat_message_msg_killer_finished (LinphoneChatMessage *msg) {
LinphoneCore *lc = linphone_chat_message_get_core(msg);
stats *counters = get_stats(lc);
counters->number_of_LinphoneMessageMsgKillerFinished++;
}
/*
* function called when the file transfer is initiated. file content should be feed into object LinphoneContent
* */
......
......@@ -1315,7 +1315,9 @@ class SwiftLangTranslator(CLikeLangTranslator):
elif _type.name == 'size':
return 'Int'
elif _type.name == 'floatant':
if _type.size is not None and _type.isref:
if _type.size is not None and _type.size == 'double':
return 'Double'
elif _type.size is not None and _type.isref:
return 'UnsafeMutablePointer<Float>'
else:
return 'Float'
......