Commit 13b9f38e authored by Ghislain MARY's avatar Ghislain MARY

Wait for the delivery of IMDN messages before storing the messages' states in DB.

parent aedd2dd2
......@@ -36,6 +36,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
chat/chat-message/chat-message-p.h
chat/chat-message/chat-message.h
chat/chat-message/imdn-message.h
chat/chat-message/imdn-message-p.h
chat/chat-message/is-composing-message.h
chat/chat-message/notification-message.h
chat/chat-message/notification-message-p.h
......
......@@ -62,7 +62,7 @@ public:
std::list<ParticipantImdnState> getParticipantsByImdnState (MainDb::ParticipantStateRetrievalFunc func) const;
void setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState, time_t stateChangeTime);
void setState (ChatMessage::State newState, bool force = false);
virtual void setState (ChatMessage::State newState, bool force = false);
void setTime (time_t time);
......
......@@ -179,8 +179,9 @@ void ChatMessagePrivate::setState (ChatMessage::State newState, bool force) {
if (state == ChatMessage::State::FileTransferDone && !hasFileTransferContent()) {
// We wait until the file has been downloaded to send the displayed IMDN
static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDisplayNotification(q->getSharedFromThis());
setState(ChatMessage::State::Displayed);
bool doNotStoreInDb = static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDisplayNotification(q->getSharedFromThis());
// Force the state so it is stored directly in DB, but when the IMDN has successfully been delivered
setState(ChatMessage::State::Displayed, doNotStoreInDb);
} else {
updateInDb();
}
......
......@@ -50,6 +50,7 @@ class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor {
friend class CpimChatMessageModifier;
friend class FileTransferChatMessageModifier;
friend class Imdn;
friend class ImdnMessagePrivate;
friend class MainDb;
friend class MainDbPrivate;
friend class RealTimeTextChatRoomPrivate;
......
/*
* imdn-message-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_IMDN_MESSAGE_P_H_
#define _L_IMDN_MESSAGE_P_H_
#include "chat/chat-message/imdn-message.h"
#include "chat/chat-message/notification-message-p.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ImdnMessagePrivate : public NotificationMessagePrivate {
private:
ImdnMessagePrivate (const ImdnMessage::Context &context)
: NotificationMessagePrivate(context.chatRoom, ChatMessage::Direction::Outgoing), context(context) {}
void setState (ChatMessage::State newState, bool force = false) override;
ImdnMessage::Context context;
L_DECLARE_PUBLIC(ImdnMessage);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_IMDN_MESSAGE_P_H_
......@@ -17,9 +17,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "chat/chat-message/notification-message-p.h"
#include "chat/chat-message/imdn-message.h"
#include "chat/chat-message/imdn-message-p.h"
#include "chat/chat-room/chat-room-p.h"
#include "content/content-disposition.h"
#include "logger/logger.h"
#include "sip-tools/sip-headers.h"
// =============================================================================
......@@ -30,38 +31,49 @@ LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
void ImdnMessagePrivate::setState (ChatMessage::State newState, bool force) {
L_Q();
if (newState == ChatMessage::State::Delivered) {
for (const auto &message : context.deliveredMessages)
message->getPrivate()->updateInDb();
for (const auto &message : context.displayedMessages)
message->getPrivate()->updateInDb();
static_pointer_cast<ChatRoom>(context.chatRoom)->getPrivate()->getImdnHandler()->onImdnMessageDelivered(q->getSharedFromThis());
}
}
// -----------------------------------------------------------------------------
ImdnMessage::ImdnMessage (
const shared_ptr<AbstractChatRoom> &chatRoom,
const list<const shared_ptr<ChatMessage>> &deliveredMessages,
const list<const shared_ptr<ChatMessage>> &displayedMessages
) : NotificationMessage(*new NotificationMessagePrivate(chatRoom, ChatMessage::Direction::Outgoing)) {
const list<shared_ptr<ChatMessage>> &deliveredMessages,
const list<shared_ptr<ChatMessage>> &displayedMessages
) : ImdnMessage(Context(chatRoom, deliveredMessages, displayedMessages)) {}
ImdnMessage::ImdnMessage (
const shared_ptr<AbstractChatRoom> &chatRoom,
const list<Imdn::MessageReason> &nonDeliveredMessages
) : ImdnMessage(Context(chatRoom, nonDeliveredMessages)) {}
ImdnMessage::ImdnMessage (const Context &context) : NotificationMessage(*new ImdnMessagePrivate(context)) {
L_D();
for (const auto &message : deliveredMessages) {
for (const auto &message : d->context.deliveredMessages) {
Content *content = new Content();
content->setContentDisposition(ContentDisposition::Notification);
content->setContentType(ContentType::Imdn);
content->setBody(Imdn::createXml(message->getImdnMessageId(), message->getTime(), Imdn::Type::Delivery, LinphoneReasonNone));
addContent(content);
}
for (const auto &message : displayedMessages) {
for (const auto &message : d->context.displayedMessages) {
Content *content = new Content();
content->setContentDisposition(ContentDisposition::Notification);
content->setContentType(ContentType::Imdn);
content->setBody(Imdn::createXml(message->getImdnMessageId(), message->getTime(), Imdn::Type::Display, LinphoneReasonNone));
addContent(content);
}
d->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
}
ImdnMessage::ImdnMessage (
const shared_ptr<AbstractChatRoom> &chatRoom,
const list<Imdn::MessageReason> &nonDeliveredMessages
) : NotificationMessage(*new NotificationMessagePrivate(chatRoom, ChatMessage::Direction::Outgoing)) {
L_D();
for (const auto &mr : nonDeliveredMessages) {
for (const auto &mr : d->context.nonDeliveredMessages) {
Content *content = new Content();
content->setContentDisposition(ContentDisposition::Notification);
content->setContentType(ContentType::Imdn);
......@@ -70,7 +82,8 @@ ImdnMessage::ImdnMessage (
}
d->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
d->setEncryptionPrevented(true);
if (!d->context.nonDeliveredMessages.empty())
d->setEncryptionPrevented(true);
}
LINPHONE_END_NAMESPACE
......@@ -21,11 +21,14 @@
#define _L_IMDN_MESSAGE_H_
#include "chat/chat-message/notification-message.h"
#include "chat/notification/imdn.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ImdnMessagePrivate;
class LINPHONE_PUBLIC ImdnMessage : public NotificationMessage {
public:
friend class ChatRoomPrivate;
......@@ -35,17 +38,35 @@ public:
virtual ~ImdnMessage () = default;
private:
struct Context {
Context (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const std::list<std::shared_ptr<ChatMessage>> &deliveredMessages,
const std::list<std::shared_ptr<ChatMessage>> &displayedMessages
) : chatRoom(chatRoom), deliveredMessages(deliveredMessages), displayedMessages(displayedMessages) {}
Context (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const std::list<Imdn::MessageReason> &nonDeliveredMessages
) : chatRoom(chatRoom), nonDeliveredMessages(nonDeliveredMessages) {}
std::shared_ptr<AbstractChatRoom> chatRoom;
std::list<std::shared_ptr<ChatMessage>> deliveredMessages;
std::list<std::shared_ptr<ChatMessage>> displayedMessages;
std::list<Imdn::MessageReason> nonDeliveredMessages;
};
ImdnMessage (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const std::list<const std::shared_ptr<ChatMessage>> &deliveredMessages,
const std::list<const std::shared_ptr<ChatMessage>> &displayedMessages
const std::list<std::shared_ptr<ChatMessage>> &deliveredMessages,
const std::list<std::shared_ptr<ChatMessage>> &displayedMessages
);
ImdnMessage (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const std::list<Imdn::MessageReason> &nonDeliveredMessages
);
ImdnMessage (const Context &context);
L_DECLARE_PRIVATE(NotificationMessage);
L_DECLARE_PRIVATE(ImdnMessage);
L_DISABLE_COPY(ImdnMessage);
};
......
......@@ -31,10 +31,13 @@ class NotificationMessagePrivate : public ChatMessagePrivate {
friend class ImdnMessage;
friend class IsComposingMessage;
private:
protected:
NotificationMessagePrivate(const std::shared_ptr<AbstractChatRoom> &cr, ChatMessage::Direction dir)
: ChatMessagePrivate(cr, dir) {}
void setState (ChatMessage::State newState, bool force = false) override {};
private:
void setDisplayNotificationRequired (bool value) override {}
void setNegativeDeliveryNotificationRequired (bool value) override {}
void setPositiveDeliveryNotificationRequired (bool value) override {}
......
......@@ -32,6 +32,9 @@
LINPHONE_BEGIN_NAMESPACE
class ImdnMessage;
class IsComposingMessage;
class ChatRoomPrivate : public AbstractChatRoomPrivate, public IsComposingListener {
public:
inline void setProxyChatRoom (AbstractChatRoom *value) { proxyChatRoom = value; }
......@@ -55,17 +58,17 @@ public:
void removeTransientEvent (const std::shared_ptr<EventLog> &eventLog) override;
std::shared_ptr<ChatMessage> createChatMessage (ChatMessage::Direction direction);
std::shared_ptr<ChatMessage> createImdnMessage (
const std::list<const std::shared_ptr<ChatMessage>> &deliveredMessages,
const std::list<const std::shared_ptr<ChatMessage>> &displayedMessages
std::shared_ptr<ImdnMessage> createImdnMessage (
const std::list<std::shared_ptr<ChatMessage>> &deliveredMessages,
const std::list<std::shared_ptr<ChatMessage>> &displayedMessages
);
std::shared_ptr<ChatMessage> createImdnMessage (const std::list<Imdn::MessageReason> &nonDeliveredMessages);
std::shared_ptr<ChatMessage> createIsComposingMessage ();
std::shared_ptr<ImdnMessage> createImdnMessage (const std::list<Imdn::MessageReason> &nonDeliveredMessages);
std::shared_ptr<IsComposingMessage> createIsComposingMessage ();
std::list<std::shared_ptr<ChatMessage>> findChatMessages (const std::string &messageId) const;
void sendDeliveryErrorNotification (const std::shared_ptr<ChatMessage> &message, LinphoneReason reason);
void sendDeliveryNotification (const std::shared_ptr<ChatMessage> &message);
void sendDisplayNotification (const std::shared_ptr<ChatMessage> &message);
bool sendDisplayNotification (const std::shared_ptr<ChatMessage> &message);
void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override;
void notifyIsComposingReceived (const Address &remoteAddress, bool isComposing);
......@@ -80,6 +83,8 @@ public:
void onIsComposingStateChanged (bool isComposing) override;
void onIsRemoteComposingStateChanged (const Address &remoteAddress, bool isComposing) override;
Imdn *getImdnHandler () const { return imdnHandler.get(); }
LinphoneChatRoom *getCChatRoom () const;
std::list<IdentityAddress> remoteIsComposing;
......
......@@ -25,6 +25,7 @@
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-message/imdn-message.h"
#include "chat/chat-message/is-composing-message.h"
#include "chat/chat-message/notification-message-p.h"
#include "chat/chat-room/chat-room-p.h"
#include "core/core-p.h"
#include "logger/logger.h"
......@@ -109,22 +110,22 @@ shared_ptr<ChatMessage> ChatRoomPrivate::createChatMessage (ChatMessage::Directi
return shared_ptr<ChatMessage>(new ChatMessage(q->getSharedFromThis(), direction));
}
shared_ptr<ChatMessage> ChatRoomPrivate::createImdnMessage (
const list<const shared_ptr<ChatMessage>> &deliveredMessages,
const list<const shared_ptr<ChatMessage>> &displayedMessages
shared_ptr<ImdnMessage> ChatRoomPrivate::createImdnMessage (
const list<shared_ptr<ChatMessage>> &deliveredMessages,
const list<shared_ptr<ChatMessage>> &displayedMessages
) {
L_Q();
return shared_ptr<ChatMessage>(new ImdnMessage(q->getSharedFromThis(), deliveredMessages, displayedMessages));
return shared_ptr<ImdnMessage>(new ImdnMessage(q->getSharedFromThis(), deliveredMessages, displayedMessages));
}
shared_ptr<ChatMessage> ChatRoomPrivate::createImdnMessage (const list<Imdn::MessageReason> &nonDeliveredMessages) {
shared_ptr<ImdnMessage> ChatRoomPrivate::createImdnMessage (const list<Imdn::MessageReason> &nonDeliveredMessages) {
L_Q();
return shared_ptr<ChatMessage>(new ImdnMessage(q->getSharedFromThis(), nonDeliveredMessages));
return shared_ptr<ImdnMessage>(new ImdnMessage(q->getSharedFromThis(), nonDeliveredMessages));
}
shared_ptr<ChatMessage> ChatRoomPrivate::createIsComposingMessage () {
shared_ptr<IsComposingMessage> ChatRoomPrivate::createIsComposingMessage () {
L_Q();
return shared_ptr<ChatMessage>(new IsComposingMessage(q->getSharedFromThis(), *isComposingHandler.get(), isComposing));
return shared_ptr<IsComposingMessage>(new IsComposingMessage(q->getSharedFromThis(), *isComposingHandler.get(), isComposing));
}
list<shared_ptr<ChatMessage>> ChatRoomPrivate::findChatMessages (const string &messageId) const {
......@@ -148,11 +149,14 @@ void ChatRoomPrivate::sendDeliveryNotification (const shared_ptr<ChatMessage> &m
imdnHandler->notifyDelivery(message);
}
void ChatRoomPrivate::sendDisplayNotification (const shared_ptr<ChatMessage> &message) {
bool ChatRoomPrivate::sendDisplayNotification (const shared_ptr<ChatMessage> &message) {
L_Q();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_displayed(policy))
if (linphone_im_notif_policy_get_send_imdn_displayed(policy)) {
imdnHandler->notifyDisplay(message);
return true;
}
return false;
}
// -----------------------------------------------------------------------------
......@@ -468,16 +472,21 @@ shared_ptr<ChatMessage> ChatRoom::findChatMessage (const string &messageId, Chat
void ChatRoom::markAsRead () {
L_D();
bool globallyMarkAsReadInDb = true;
CorePrivate *dCore = getCore()->getPrivate();
for (auto &chatMessage : dCore->mainDb->getUnreadChatMessages(d->chatRoomId)) {
// Do not send display notification for file transfer until it has been downloaded (it won't have a file transfer content anymore)
if (!chatMessage->getPrivate()->hasFileTransferContent()) {
d->sendDisplayNotification(chatMessage);
chatMessage->getPrivate()->setState(ChatMessage::State::Displayed, true); // True will ensure the setState won't update the database so it will be done below by the markChatMessagesAsRead
bool doNotStoreInDb = d->sendDisplayNotification(chatMessage);
// Force the state so it is stored directly in DB, but when the IMDN has successfully been delivered
chatMessage->getPrivate()->setState(ChatMessage::State::Displayed, doNotStoreInDb);
if (doNotStoreInDb)
globallyMarkAsReadInDb = false;
}
}
dCore->mainDb->markChatMessagesAsRead(d->chatRoomId);
if (globallyMarkAsReadInDb)
dCore->mainDb->markChatMessagesAsRead(d->chatRoomId);
}
LINPHONE_END_NAMESPACE
......@@ -32,6 +32,7 @@ class LINPHONE_PUBLIC ChatRoom : public AbstractChatRoom {
public:
friend class ChatMessagePrivate;
friend class Imdn;
friend class ImdnMessagePrivate;
friend class ProxyChatRoomPrivate;
L_OVERRIDE_SHARED_FROM_THIS(ChatRoom);
......
......@@ -20,6 +20,7 @@
#include <algorithm>
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-message/imdn-message.h"
#include "chat/chat-room/chat-room-p.h"
#include "core/core.h"
#include "logger/logger.h"
......@@ -74,6 +75,12 @@ void Imdn::notifyDisplay (const shared_ptr<ChatMessage> &message) {
// -----------------------------------------------------------------------------
void Imdn::onImdnMessageDelivered (const std::shared_ptr<ImdnMessage> &message) {
sentImdnMessages.remove(message);
}
// -----------------------------------------------------------------------------
string Imdn::createXml (const string &id, time_t timestamp, Imdn::Type imdnType, LinphoneReason reason) {
char *datetime = linphone_timestamp_to_rfc3339_string(timestamp);
Xsd::Imdn::Imdn imdn(id, datetime);
......@@ -153,10 +160,22 @@ int Imdn::timerExpired (void *data, unsigned int revents) {
// -----------------------------------------------------------------------------
void Imdn::send () {
if (!deliveredMessages.empty() || !displayedMessages.empty())
chatRoom->getPrivate()->createImdnMessage(deliveredMessages, displayedMessages)->send();
if (!nonDeliveredMessages.empty())
chatRoom->getPrivate()->createImdnMessage(nonDeliveredMessages)->send();
bool networkReachable = linphone_core_is_network_reachable(chatRoom->getCore()->getCCore());
if (!deliveredMessages.empty() || !displayedMessages.empty()) {
auto imdnMessage = chatRoom->getPrivate()->createImdnMessage(deliveredMessages, displayedMessages);
sentImdnMessages.push_back(imdnMessage);
if (networkReachable)
imdnMessage->send();
deliveredMessages.clear();
displayedMessages.clear();
}
if (!nonDeliveredMessages.empty()) {
auto imdnMessage = chatRoom->getPrivate()->createImdnMessage(nonDeliveredMessages);
sentImdnMessages.push_back(imdnMessage);
if (networkReachable)
imdnMessage->send();
nonDeliveredMessages.clear();
}
}
void Imdn::startTimer () {
......
......@@ -32,6 +32,7 @@ LINPHONE_BEGIN_NAMESPACE
class ChatMessage;
class ChatRoom;
class ImdnMessage;
class Imdn {
public:
......@@ -55,6 +56,8 @@ public:
void notifyDeliveryError (const std::shared_ptr<ChatMessage> &message, LinphoneReason reason);
void notifyDisplay (const std::shared_ptr<ChatMessage> &message);
void onImdnMessageDelivered (const std::shared_ptr<ImdnMessage> &message);
static std::string createXml (const std::string &id, time_t time, Imdn::Type imdnType, LinphoneReason reason);
static void parse (const std::shared_ptr<ChatMessage> &chatMessage);
......@@ -67,9 +70,10 @@ private:
private:
ChatRoom *chatRoom = nullptr;
std::list<const std::shared_ptr<ChatMessage>> deliveredMessages;
std::list<const std::shared_ptr<ChatMessage>> displayedMessages;
std::list<std::shared_ptr<ChatMessage>> deliveredMessages;
std::list<std::shared_ptr<ChatMessage>> displayedMessages;
std::list<MessageReason> nonDeliveredMessages;
std::list<std::shared_ptr<ImdnMessage>> sentImdnMessages;
belle_sip_source_t *timer = nullptr;
BackgroundTask bgTask { "IMDN sending" };
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment