Commit 2888e843 authored by Ghislain MARY's avatar Ghislain MARY

Add ImdnMessage class.

parent 75c981df
......@@ -35,6 +35,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
call/remote-conference-call.h
chat/chat-message/chat-message-p.h
chat/chat-message/chat-message.h
chat/chat-message/imdn-message.h
chat/chat-message/is-composing-message.h
chat/chat-message/notification-message.h
chat/chat-message/notification-message-p.h
......@@ -193,6 +194,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
call/local-conference-call.cpp
call/remote-conference-call.cpp
chat/chat-message/chat-message.cpp
chat/chat-message/imdn-message.cpp
chat/chat-message/is-composing-message.cpp
chat/chat-message/notification-message.cpp
chat/chat-room/abstract-chat-room.cpp
......
......@@ -154,8 +154,6 @@ public:
bool downloadFile ();
void sendImdn (Imdn::Type imdnType, LinphoneReason reason);
void notifyReceiving ();
LinphoneReason receive ();
void send ();
......
......@@ -179,7 +179,7 @@ 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
q->sendDisplayNotification();
static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDisplayNotification(q->getSharedFromThis());
setState(ChatMessage::State::Displayed);
} else {
updateInDb();
......@@ -454,26 +454,6 @@ void ChatMessagePrivate::setChatRoom (const shared_ptr<AbstractChatRoom> &cr) {
// -----------------------------------------------------------------------------
void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) {
L_Q();
auto chatRoomPrivate = static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate());
shared_ptr<ChatMessage> msg = chatRoomPrivate->createNotificationMessage(ChatMessage::Direction::Outgoing);
Content *content = new Content();
content->setContentDisposition(ContentDisposition::Notification);
content->setContentType(ContentType::Imdn);
content->setBody(Imdn::createXml(imdnId, time, imdnType, reason));
msg->addContent(content);
if (reason != LinphoneReasonNone)
msg->getPrivate()->setEncryptionPrevented(true);
msg->getPrivate()->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
msg->getPrivate()->send();
}
static void forceUtf8Content (Content &content) {
// TODO: Deal with other content type in the future.
ContentType contentType = content.getContentType();
......@@ -524,7 +504,7 @@ void ChatMessagePrivate::notifyReceiving () {
q->getChatRoom()->getPrivate()->notifyChatMessageReceived(q->getSharedFromThis());
if (getPositiveDeliveryNotificationRequired())
q->sendDeliveryNotification(LinphoneReasonNone);
static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDeliveryNotification(q->getSharedFromThis());
}
LinphoneReason ChatMessagePrivate::receive () {
......@@ -549,7 +529,10 @@ LinphoneReason ChatMessagePrivate::receive () {
chatRoom->getPrivate()->notifyUndecryptableChatMessageReceived(q->getSharedFromThis());
reason = linphone_error_code_to_reason(errorCode);
if (getNegativeDeliveryNotificationRequired()) {
q->sendDeliveryNotification(reason);
static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDeliveryErrorNotification(
q->getSharedFromThis(),
reason
);
}
return reason;
} else if (result == ChatMessageModifier::Result::Suspended) {
......@@ -635,7 +618,10 @@ LinphoneReason ChatMessagePrivate::receive () {
if (errorCode > 0) {
reason = linphone_error_code_to_reason(errorCode);
if (getNegativeDeliveryNotificationRequired()) {
q->sendDeliveryNotification(reason);
static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDeliveryErrorNotification(
q->getSharedFromThis(),
reason
);
}
return reason;
}
......@@ -1123,22 +1109,6 @@ void ChatMessage::send () {
getChatRoom()->getPrivate()->sendChatMessage(getSharedFromThis());
}
void ChatMessage::sendDeliveryNotification (LinphoneReason reason) {
L_D();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_delivered(policy))
d->sendImdn(Imdn::Type::Delivery, reason);
}
void ChatMessage::sendDisplayNotification () {
L_D();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_displayed(policy))
d->sendImdn(Imdn::Type::Display, LinphoneReasonNone);
}
bool ChatMessage::downloadFile(FileTransferContent *fileTransferContent) {
L_D();
return d->fileTransferChatMessageModifier.downloadFile(getSharedFromThis(), fileTransferContent);
......
......@@ -66,8 +66,6 @@ public:
// ----- TODO: Remove me.
void cancelFileTransfer ();
int putCharacter (uint32_t character);
void sendDeliveryNotification (LinphoneReason reason);
void sendDisplayNotification ();
void setIsSecured (bool isSecured);
// ----- TODO: Remove me.
......
/*
* imdn-message.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 "chat/chat-message/notification-message-p.h"
#include "chat/chat-message/imdn-message.h"
#include "content/content-disposition.h"
#include "sip-tools/sip-headers.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
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)) {
L_D();
for (const auto &message : 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) {
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) {
Content *content = new Content();
content->setContentDisposition(ContentDisposition::Notification);
content->setContentType(ContentType::Imdn);
content->setBody(Imdn::createXml(mr.message->getImdnMessageId(), mr.message->getTime(), Imdn::Type::Delivery, mr.reason));
addContent(content);
}
d->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
d->setEncryptionPrevented(true);
}
LINPHONE_END_NAMESPACE
/*
* imdn-message.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_H_
#define _L_IMDN_MESSAGE_H_
#include "chat/chat-message/notification-message.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class LINPHONE_PUBLIC ImdnMessage : public NotificationMessage {
public:
friend class ChatRoomPrivate;
L_OVERRIDE_SHARED_FROM_THIS(ImdnMessage);
virtual ~ImdnMessage () = default;
private:
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
);
ImdnMessage (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const std::list<Imdn::MessageReason> &nonDeliveredMessages
);
L_DECLARE_PRIVATE(NotificationMessage);
L_DISABLE_COPY(ImdnMessage);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_IMDN_MESSAGE_H_
......@@ -28,6 +28,7 @@
LINPHONE_BEGIN_NAMESPACE
class NotificationMessagePrivate : public ChatMessagePrivate {
friend class ImdnMessage;
friend class IsComposingMessage;
private:
......
......@@ -25,6 +25,7 @@
#include "abstract-chat-room-p.h"
#include "chat-room-id.h"
#include "chat-room.h"
#include "chat/notification/imdn.h"
#include "chat/notification/is-composing.h"
// =============================================================================
......@@ -54,10 +55,18 @@ 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<ChatMessage> createImdnMessage (const std::list<Imdn::MessageReason> &nonDeliveredMessages);
std::shared_ptr<ChatMessage> createIsComposingMessage ();
std::shared_ptr<ChatMessage> createNotificationMessage (ChatMessage::Direction direction);
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);
void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override;
void notifyIsComposingReceived (const Address &remoteAddress, bool isComposing);
void notifyStateChanged ();
......@@ -86,6 +95,7 @@ private:
time_t creationTime = std::time(nullptr);
time_t lastUpdateTime = std::time(nullptr);
std::unique_ptr<Imdn> imdnHandler;
std::unique_ptr<IsComposing> isComposingHandler;
bool isComposing = false;
......
......@@ -23,8 +23,8 @@
#include "c-wrapper/c-wrapper.h"
#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.h"
#include "chat/chat-room/chat-room-p.h"
#include "core/core-p.h"
#include "logger/logger.h"
......@@ -109,14 +109,22 @@ shared_ptr<ChatMessage> ChatRoomPrivate::createChatMessage (ChatMessage::Directi
return shared_ptr<ChatMessage>(new ChatMessage(q->getSharedFromThis(), direction));
}
shared_ptr<ChatMessage> ChatRoomPrivate::createIsComposingMessage () {
shared_ptr<ChatMessage> ChatRoomPrivate::createImdnMessage (
const list<const shared_ptr<ChatMessage>> &deliveredMessages,
const list<const shared_ptr<ChatMessage>> &displayedMessages
) {
L_Q();
return shared_ptr<ChatMessage>(new IsComposingMessage(q->getSharedFromThis(), *isComposingHandler.get(), isComposing));
return shared_ptr<ChatMessage>(new ImdnMessage(q->getSharedFromThis(), deliveredMessages, displayedMessages));
}
shared_ptr<ChatMessage> ChatRoomPrivate::createNotificationMessage (ChatMessage::Direction direction) {
shared_ptr<ChatMessage> ChatRoomPrivate::createImdnMessage (const list<Imdn::MessageReason> &nonDeliveredMessages) {
L_Q();
return shared_ptr<ChatMessage>(new NotificationMessage(q->getSharedFromThis(), direction));
return shared_ptr<ChatMessage>(new ImdnMessage(q->getSharedFromThis(), nonDeliveredMessages));
}
shared_ptr<ChatMessage> ChatRoomPrivate::createIsComposingMessage () {
L_Q();
return shared_ptr<ChatMessage>(new IsComposingMessage(q->getSharedFromThis(), *isComposingHandler.get(), isComposing));
}
list<shared_ptr<ChatMessage>> ChatRoomPrivate::findChatMessages (const string &messageId) const {
......@@ -126,6 +134,29 @@ list<shared_ptr<ChatMessage>> ChatRoomPrivate::findChatMessages (const string &m
// -----------------------------------------------------------------------------
void ChatRoomPrivate::sendDeliveryErrorNotification (const shared_ptr<ChatMessage> &message, LinphoneReason reason) {
L_Q();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_delivered(policy))
imdnHandler->notifyDeliveryError(message, reason);
}
void ChatRoomPrivate::sendDeliveryNotification (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_delivered(policy))
imdnHandler->notifyDelivery(message);
}
void 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))
imdnHandler->notifyDisplay(message);
}
// -----------------------------------------------------------------------------
void ChatRoomPrivate::notifyChatMessageReceived (const shared_ptr<ChatMessage> &chatMessage) {
L_Q();
LinphoneChatRoom *cr = getCChatRoom();
......@@ -279,6 +310,7 @@ ChatRoom::ChatRoom (ChatRoomPrivate &p, const shared_ptr<Core> &core, const Chat
L_D();
d->chatRoomId = chatRoomId;
d->imdnHandler.reset(new Imdn(this));
d->isComposingHandler.reset(new IsComposing(core->getCCore(), d));
}
......@@ -440,7 +472,7 @@ void ChatRoom::markAsRead () {
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()) {
chatMessage->sendDisplayNotification();
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
}
}
......
......@@ -31,6 +31,7 @@ class ChatRoomPrivate;
class LINPHONE_PUBLIC ChatRoom : public AbstractChatRoom {
public:
friend class ChatMessagePrivate;
friend class Imdn;
friend class ProxyChatRoomPrivate;
L_OVERRIDE_SHARED_FROM_THIS(ChatRoom);
......
......@@ -17,8 +17,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <algorithm>
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-room/chat-room.h"
#include "chat/chat-room/chat-room-p.h"
#include "core/core.h"
#include "logger/logger.h"
......@@ -32,6 +34,46 @@ LINPHONE_BEGIN_NAMESPACE
const string Imdn::imdnPrefix = "/imdn:imdn";
// -----------------------------------------------------------------------------
Imdn::Imdn (ChatRoom *chatRoom) : chatRoom(chatRoom) {}
Imdn::~Imdn () {
stopTimer();
}
// -----------------------------------------------------------------------------
void Imdn::notifyDelivery (const shared_ptr<ChatMessage> &message) {
if (find(deliveredMessages.begin(), deliveredMessages.end(), message) == deliveredMessages.end()) {
deliveredMessages.push_back(message);
startTimer();
}
}
void Imdn::notifyDeliveryError (const shared_ptr<ChatMessage> &message, LinphoneReason reason) {
auto it = find_if(nonDeliveredMessages.begin(), nonDeliveredMessages.end(), [message](const MessageReason mr) {
return message == mr.message;
});
if (it == nonDeliveredMessages.end()) {
nonDeliveredMessages.emplace_back(message, reason);
startTimer();
}
}
void Imdn::notifyDisplay (const shared_ptr<ChatMessage> &message) {
auto it = find(deliveredMessages.begin(), deliveredMessages.end(), message);
if (it != deliveredMessages.end())
deliveredMessages.erase(it);
if (find(displayedMessages.begin(), displayedMessages.end(), message) == displayedMessages.end()) {
displayedMessages.push_back(message);
startTimer();
}
}
// -----------------------------------------------------------------------------
string Imdn::createXml (const string &id, time_t time, Imdn::Type imdnType, LinphoneReason reason) {
xmlBufferPtr buf;
xmlTextWriterPtr writer;
......@@ -144,6 +186,8 @@ void Imdn::parse (const shared_ptr<ChatMessage> &chatMessage) {
linphone_xmlparsing_context_destroy(xmlCtx);
}
// -----------------------------------------------------------------------------
void Imdn::parse (const shared_ptr<ChatMessage> &imdnMessage, xmlparsing_context_t *xmlCtx) {
char xpathStr[MAX_XPATH_LENGTH];
char *messageIdStr = nullptr;
......@@ -208,4 +252,38 @@ void Imdn::parse (const shared_ptr<ChatMessage> &imdnMessage, xmlparsing_context
linphone_free_xml_text_content(datetimeStr);
}
int Imdn::timerExpired (void *data, unsigned int revents) {
Imdn *d = reinterpret_cast<Imdn *>(data);
d->stopTimer();
d->send();
return BELLE_SIP_STOP;
}
// -----------------------------------------------------------------------------
void Imdn::send () {
if (!deliveredMessages.empty() || !displayedMessages.empty())
chatRoom->getPrivate()->createImdnMessage(deliveredMessages, displayedMessages)->send();
if (!nonDeliveredMessages.empty())
chatRoom->getPrivate()->createImdnMessage(nonDeliveredMessages)->send();
}
void Imdn::startTimer () {
unsigned int duration = 500;
if (!timer)
timer = chatRoom->getCore()->getCCore()->sal->create_timer(timerExpired, this, duration, "imdn timeout");
else
belle_sip_source_set_timeout(timer, duration);
}
void Imdn::stopTimer () {
if (timer) {
auto core = chatRoom->getCore()->getCCore();
if (core && core->sal)
core->sal->cancel_timer(timer);
belle_sip_object_unref(timer);
timer = nullptr;
}
}
LINPHONE_END_NAMESPACE
......@@ -28,6 +28,7 @@
LINPHONE_BEGIN_NAMESPACE
class ChatMessage;
class ChatRoom;
class Imdn {
......@@ -37,14 +38,40 @@ public:
Display
};
struct MessageReason {
MessageReason (const std::shared_ptr<ChatMessage> &message, LinphoneReason reason)
: message(message), reason(reason) {}
const std::shared_ptr<ChatMessage> message;
LinphoneReason reason;
};
Imdn (ChatRoom *chatRoom);
~Imdn ();
void notifyDelivery (const std::shared_ptr<ChatMessage> &message);
void notifyDeliveryError (const std::shared_ptr<ChatMessage> &message, LinphoneReason reason);
void notifyDisplay (const std::shared_ptr<ChatMessage> &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);
private:
static void parse (const std::shared_ptr<ChatMessage> &chatMessage, xmlparsing_context_t *xmlCtx);
static int timerExpired (void *data, unsigned int revents);
void send ();
void startTimer ();
void stopTimer ();
private:
static const std::string imdnPrefix;
ChatRoom *chatRoom = nullptr;
std::list<const std::shared_ptr<ChatMessage>> deliveredMessages;
std::list<const std::shared_ptr<ChatMessage>> displayedMessages;
std::list<MessageReason> nonDeliveredMessages;
belle_sip_source_t *timer = nullptr;
};
LINPHONE_END_NAMESPACE
......
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