Commit d1dc2238 authored by Ghislain MARY's avatar Ghislain MARY

Handle imdn namespace and Disposition-Notification header in CPIM.

parent f4f642a4
......@@ -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/notification-message.h
chat/chat-room/abstract-chat-room-p.h
chat/chat-room/abstract-chat-room.h
chat/chat-room/basic-chat-room-p.h
......@@ -190,6 +191,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/notification-message.cpp
chat/chat-room/abstract-chat-room.cpp
chat/chat-room/basic-chat-room.cpp
chat/chat-room/basic-to-client-group-chat-room.cpp
......
......@@ -44,6 +44,7 @@ class ChatMessagePrivate : public ObjectPrivate {
friend class CpimChatMessageModifier;
friend class EncryptionChatMessageModifier;
friend class MultipartChatMessageModifier;
friend class NotificationMessagePrivate;
public:
enum Step {
......@@ -99,6 +100,13 @@ public:
SalOp *getSalOp () const;
void setSalOp (SalOp *op);
bool getDisplayNotificationRequired () const { return displayNotificationRequired; }
bool getNegativeDeliveryNotificationRequired () const { return negativeDeliveryNotificationRequired; }
bool getPositiveDeliveryNotificationRequired () const { return positiveDeliveryNotificationRequired; }
virtual void setDisplayNotificationRequired (bool value) { displayNotificationRequired = value; }
virtual void setNegativeDeliveryNotificationRequired (bool value) { negativeDeliveryNotificationRequired = value; }
virtual void setPositiveDeliveryNotificationRequired (bool value) { positiveDeliveryNotificationRequired = value; }
SalCustomHeader *getSalCustomHeaders () const;
void setSalCustomHeaders (SalCustomHeader *headers);
......@@ -156,11 +164,20 @@ public:
void updateInDb ();
private:
ChatMessagePrivate(const std::shared_ptr<AbstractChatRoom> &cr, ChatMessage::Direction dir);
static bool validStateTransition (ChatMessage::State currentState, ChatMessage::State newState);
public:
mutable MainDbChatMessageKey dbKey;
protected:
bool displayNotificationRequired = true;
bool negativeDeliveryNotificationRequired = true;
bool positiveDeliveryNotificationRequired = true;
bool toBeStored = true;
private:
// TODO: Clean attributes.
time_t time = ::ms_time(0); // TODO: Change me in all files.
std::string imdnId;
......@@ -189,10 +206,6 @@ private:
// TODO: Remove my comment. VARIABLES OK.
// Do not expose.
public:
mutable MainDbChatMessageKey dbKey;
private:
std::weak_ptr<AbstractChatRoom> chatRoom;
ChatRoomId chatRoomId;
IdentityAddress fromAddress;
......@@ -204,7 +217,6 @@ private:
std::list<Content* > contents;
bool encryptionPrevented = false;
bool toBeStored = true;
mutable bool contentsNotLoadedFromDatabase = false;
L_DECLARE_PUBLIC(ChatMessage);
};
......
......@@ -457,7 +457,8 @@ void ChatMessagePrivate::setChatRoom (const shared_ptr<AbstractChatRoom> &cr) {
void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) {
L_Q();
shared_ptr<ChatMessage> msg = q->getChatRoom()->createChatMessage();
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);
......@@ -468,7 +469,6 @@ void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) {
if (reason != LinphoneReasonNone)
msg->getPrivate()->setEncryptionPrevented(true);
msg->setToBeStored(false);
msg->getPrivate()->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
msg->getPrivate()->send();
......@@ -523,9 +523,8 @@ void ChatMessagePrivate::notifyReceiving () {
// Legacy
q->getChatRoom()->getPrivate()->notifyChatMessageReceived(q->getSharedFromThis());
if ((getContentType() != ContentType::Imdn) && (getContentType() != ContentType::ImIsComposing)) {
if (getPositiveDeliveryNotificationRequired())
q->sendDeliveryNotification(LinphoneReasonNone);
}
}
LinphoneReason ChatMessagePrivate::receive () {
......@@ -894,7 +893,10 @@ bool ChatMessagePrivate::validStateTransition (ChatMessage::State currentState,
// -----------------------------------------------------------------------------
ChatMessage::ChatMessage (const shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction) :
Object(*new ChatMessagePrivate(chatRoom,direction)), CoreAccessor(chatRoom->getCore()) {
Object(*new ChatMessagePrivate(chatRoom, direction)), CoreAccessor(chatRoom->getCore()) {
}
ChatMessage::ChatMessage (ChatMessagePrivate &p) : Object(p), CoreAccessor(p.getPublic()->getChatRoom()->getCore()) {
}
ChatMessage::~ChatMessage () {
......
......@@ -61,7 +61,7 @@ public:
L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_MESSAGE_STATE);
L_DECLARE_ENUM(Direction, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION);
~ChatMessage ();
virtual ~ChatMessage ();
// ----- TODO: Remove me.
void cancelFileTransfer ();
......@@ -93,7 +93,7 @@ public:
bool isReadOnly () const;
bool getToBeStored () const;
void setToBeStored (bool value);
virtual void setToBeStored (bool value);
std::list<ParticipantImdnState> getParticipantsThatHaveDisplayed () const;
std::list<ParticipantImdnState> getParticipantsThatHaveReceived () const;
......@@ -114,6 +114,9 @@ public:
bool downloadFile (FileTransferContent *content);
bool isFileTransferInProgress();
protected:
explicit ChatMessage (ChatMessagePrivate &p);
private:
ChatMessage (const std::shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction);
......
/*
* notification-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/chat-message-p.h"
#include "chat/chat-message/notification-message.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
class NotificationMessagePrivate : public ChatMessagePrivate {
private:
NotificationMessagePrivate(const std::shared_ptr<AbstractChatRoom> &cr, ChatMessage::Direction dir)
: ChatMessagePrivate(cr, dir) {}
void setDisplayNotificationRequired (bool value) override {}
void setNegativeDeliveryNotificationRequired (bool value) override {}
void setPositiveDeliveryNotificationRequired (bool value) override {}
L_DECLARE_PUBLIC(NotificationMessage);
};
// -----------------------------------------------------------------------------
NotificationMessage::NotificationMessage (const shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction) :
ChatMessage(*new NotificationMessagePrivate(chatRoom, direction)) {
L_D();
d->displayNotificationRequired = false;
d->negativeDeliveryNotificationRequired = false;
d->positiveDeliveryNotificationRequired = false;
d->toBeStored = false;
}
void NotificationMessage::setToBeStored (bool value) {
}
LINPHONE_END_NAMESPACE
/*
* notification-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_NOTIFICATION_MESSAGE_H_
#define _L_NOTIFICATION_MESSAGE_H_
#include "chat/chat-message/chat-message.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class NotificationMessagePrivate;
class LINPHONE_PUBLIC NotificationMessage : public ChatMessage {
public:
friend class ChatRoomPrivate;
L_OVERRIDE_SHARED_FROM_THIS(NotificationMessage);
virtual ~NotificationMessage () = default;
void setToBeStored (bool value) override;
private:
NotificationMessage (const std::shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction);
L_DECLARE_PRIVATE(NotificationMessage);
L_DISABLE_COPY(NotificationMessage);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_NOTIFICATION_MESSAGE_H_
......@@ -54,6 +54,7 @@ public:
void removeTransientEvent (const std::shared_ptr<EventLog> &eventLog) override;
std::shared_ptr<ChatMessage> createChatMessage (ChatMessage::Direction direction);
std::shared_ptr<ChatMessage> createNotificationMessage (ChatMessage::Direction direction);
std::list<std::shared_ptr<ChatMessage>> findChatMessages (const std::string &messageId) const;
void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override;
......
......@@ -23,6 +23,7 @@
#include "c-wrapper/c-wrapper.h"
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-message/notification-message.h"
#include "chat/chat-room/chat-room-p.h"
#include "core/core-p.h"
#include "sip-tools/sip-headers.h"
......@@ -84,8 +85,7 @@ void ChatRoomPrivate::sendIsComposingNotification () {
content->setContentType(ContentType::ImIsComposing);
content->setBody(payload);
shared_ptr<ChatMessage> chatMessage = createChatMessage(ChatMessage::Direction::Outgoing);
chatMessage->setToBeStored(false);
shared_ptr<ChatMessage> chatMessage = createNotificationMessage(ChatMessage::Direction::Outgoing);
chatMessage->addContent(content);
chatMessage->getPrivate()->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
chatMessage->getPrivate()->addSalCustomHeader("Expires", "0");
......@@ -121,6 +121,11 @@ shared_ptr<ChatMessage> ChatRoomPrivate::createChatMessage (ChatMessage::Directi
return shared_ptr<ChatMessage>(new ChatMessage(q->getSharedFromThis(), direction));
}
shared_ptr<ChatMessage> ChatRoomPrivate::createNotificationMessage (ChatMessage::Direction direction) {
L_Q();
return shared_ptr<ChatMessage>(new NotificationMessage(q->getSharedFromThis(), direction));
}
list<shared_ptr<ChatMessage>> ChatRoomPrivate::findChatMessages (const string &messageId) const {
L_Q();
return q->getCore()->getPrivate()->mainDb->findChatMessages(q->getChatRoomId(), messageId);
......@@ -214,26 +219,21 @@ LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessag
reason = msg->getPrivate()->receive();
if (reason == LinphoneReasonNotAcceptable || reason == LinphoneReasonUnknown) {
/* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */
reason = LinphoneReasonNone;
goto end;
// Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt
return LinphoneReasonNone;
}
if (msg->getPrivate()->getContentType() == ContentType::ImIsComposing) {
onIsComposingReceived(msg->getFromAddress(), msg->getPrivate()->getText());
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) {
goto end;
}
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1)
return reason;
} else if (msg->getPrivate()->getContentType() == ContentType::Imdn) {
onImdnReceived(msg);
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) {
goto end;
}
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1)
return reason;
}
onChatMessageReceived(msg);
end:
return reason;
}
......
......@@ -17,6 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/utils/utils.h"
#include "address/address.h"
#include "chat/chat-message/chat-message-p.h"
#include "chat/cpim/cpim.h"
......@@ -42,12 +44,33 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr<Ch
Cpim::ToHeader cpimToHeader;
cpimToHeader.setValue(cpimAddressAsString(message->getToAddress()));
cpimMessage.addMessageHeader(cpimToHeader);
char token[13];
belle_sip_random_token(token, sizeof(token));
Cpim::MessageIdHeader cpimMessageIdHeader;
cpimMessageIdHeader.setValue(token);
cpimMessage.addMessageHeader(cpimMessageIdHeader);
message->getPrivate()->setImdnMessageId(token);
if (message->getPrivate()->getPositiveDeliveryNotificationRequired()
|| message->getPrivate()->getDisplayNotificationRequired()
) {
const string imdnNamespace = "imdn";
Cpim::NsHeader cpimNsHeader;
cpimNsHeader.setValue(imdnNamespace + " <urn:ietf:params:imdn>");
cpimMessage.addMessageHeader(cpimNsHeader);
char token[13];
belle_sip_random_token(token, sizeof(token));
Cpim::GenericHeader cpimMessageIdHeader;
cpimMessageIdHeader.setName("Message-ID"); // TODO: Replace by imdnNamespace + ".Message-ID");
cpimMessageIdHeader.setValue(token);
cpimMessage.addMessageHeader(cpimMessageIdHeader);
message->getPrivate()->setImdnMessageId(token);
Cpim::GenericHeader dispositionNotificationHeader;
dispositionNotificationHeader.setName(imdnNamespace + ".Disposition-Notification");
vector<string> dispositionNotificationValues;
if (message->getPrivate()->getPositiveDeliveryNotificationRequired())
dispositionNotificationValues.emplace_back("positive-delivery");
if (message->getPrivate()->getDisplayNotificationRequired())
dispositionNotificationValues.emplace_back("display");
dispositionNotificationHeader.setValue(Utils::join(dispositionNotificationValues, ", "));
cpimMessage.addMessageHeader(dispositionNotificationHeader);
}
const Content *content;
if (!message->getInternalContent().isEmpty()) {
......@@ -125,17 +148,45 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr<Ch
}
newContent.setBody(cpimMessage->getContent());
message->getPrivate()->setPositiveDeliveryNotificationRequired(false);
message->getPrivate()->setNegativeDeliveryNotificationRequired(false);
message->getPrivate()->setDisplayNotificationRequired(false);
Address cpimFromAddress;
Address cpimToAddress;
l = cpimMessage->getMessageHeaders();
if (l) {
string imdnNamespace = "";
for (const auto &header : *l.get()) {
if (header->getName() == "NS") {
string val = header->getValue();
size_t startPos = 0;
startPos = val.find("<", startPos);
if (startPos == string::npos)
break;
size_t endPos = 0;
endPos = val.find(">", startPos);
if (endPos == string::npos)
break;
if (val.substr(startPos, endPos) == "<urn:ietf:params:imdn>")
imdnNamespace = Utils::trim(val.substr(0, startPos));
}
}
for (const auto &header : *l.get()) {
if (header->getName() == "From")
cpimFromAddress = Address(header->getValue());
else if (header->getName() == "To")
cpimToAddress = Address(header->getValue());
else if (header->getName() == "Message-ID")
else if ((header->getName() == "Message-ID") || (header->getName() == (imdnNamespace + ".Message-ID")))
message->getPrivate()->setImdnMessageId(header->getValue());
else if ((header->getName() == (imdnNamespace + ".Disposition-Notification"))) {
vector<string> values = Utils::split(header->getValue(), ", ");
for (const auto &value : values)
if (value == "positive-delivery")
message->getPrivate()->setPositiveDeliveryNotificationRequired(true);
else if (value == "display")
message->getPrivate()->setDisplayNotificationRequired(true);
}
}
}
......
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