Commit 0db6249a authored by Sylvain Berfini's avatar Sylvain Berfini 🎩

Simple ChatMessageMultipartModifier created + fixed a few things related to ChatMessages

parent 5dc6b956
......@@ -152,7 +152,7 @@ private:
bool isFileTransferInProgressAndValid();
int startHttpTransfer(std::string url, std::string action, belle_http_request_listener_callbacks_t *cbs);
void releaseHttpRequest();
void createFileTransferInformationsFromVndGsmaRcsFtHttpXml();
void createFileTransferInformationsFromVndGsmaRcsFtHttpXml(std::string body);
L_DECLARE_PUBLIC(ChatMessage);
};
......
......@@ -888,12 +888,12 @@ void ChatMessagePrivate::releaseHttpRequest() {
}
}
void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml() {
void ChatMessagePrivate::createFileTransferInformationsFromVndGsmaRcsFtHttpXml(string body) {
xmlChar *file_url = NULL;
xmlDocPtr xmlMessageBody;
xmlNodePtr cur;
/* parse the msg body to get all informations from it */
xmlMessageBody = xmlParseDoc((const xmlChar *)getText().c_str());
xmlMessageBody = xmlParseDoc((const xmlChar *)body.c_str());
LinphoneContent *content = linphone_content_new();
setFileTransferInformation(content);
......@@ -1005,9 +1005,21 @@ LinphoneReason ChatMessagePrivate::receive() {
// End of message modification
// ---------------------------------------
if ((errorCode <= 0) && (linphone_core_is_content_type_supported(chatRoom->getCore(), getContentType().asString().c_str()) == FALSE)) {
errorCode = 415;
lError() << "Unsupported MESSAGE (content-type " << getContentType().asString() << " not recognized)";
if (errorCode <= 0) {
bool foundSupportContentType = false;
for (auto it = contents.begin(); it != contents.end(); it++) {
if (linphone_core_is_content_type_supported(chatRoom->getCore(), it->getContentType().asString().c_str())) {
foundSupportContentType = true;
break;
} else {
lError() << "Unsupported content-type: " << it->getContentType().asString();
}
}
if (!foundSupportContentType) {
errorCode = 415;
lError() << "No content-type in the contents list is supported...";
}
}
if (errorCode > 0) {
......@@ -1016,11 +1028,13 @@ LinphoneReason ChatMessagePrivate::receive() {
return reason;
}
if (getContentType() == ContentType::FileTransfer) {
createFileTransferInformationsFromVndGsmaRcsFtHttpXml();
store = true;
} else if (getContentType() == ContentType::PlainText) {
store = true;
for (auto it = contents.begin(); it != contents.end(); it++) {
if (it->getContentType() == ContentType::FileTransfer) {
store = true;
createFileTransferInformationsFromVndGsmaRcsFtHttpXml(it->getBodyAsString());
} else if (it->getContentType() == ContentType::PlainText) {
store = true;
}
}
if (store) {
......
......@@ -402,7 +402,7 @@ LinphoneReason ChatRoomPrivate::messageReceived (SalOp *op, const SalMessage *sa
Content content;
content.setContentType(salMsg->content_type);
content.setBody(salMsg->text ? salMsg->text : "");
msg->addContent(content);
msg->setInternalContent(content);
msg->setToAddress(op->get_to() ? op->get_to() : linphone_core_get_identity(core));
msg->setFromAddress(peerAddress);
......
......@@ -24,7 +24,7 @@
#include "content/content.h"
#include "address/address.h"
#include "logger/logger.h"
#include "chat/chat-message-p.h"
#include "chat/chat-message.h"
// =============================================================================
......
......@@ -26,7 +26,7 @@
#include "content/content.h"
#include "address/address.h"
#include "chat/chat-room.h"
#include "chat/chat-message-p.h"
#include "chat/chat-message.h"
// =============================================================================
......
......@@ -18,8 +18,11 @@
*/
#include "multipart-chat-message-modifier.h"
#include "address/address.h"
#include "chat/chat-message-p.h"
#include "chat/chat-room.h"
#include "chat/chat-message.h"
#include "logger/logger.h"
// =============================================================================
......@@ -29,15 +32,86 @@ LINPHONE_BEGIN_NAMESPACE
ChatMessageModifier::Result MultipartChatMessageModifier::encode (shared_ptr<ChatMessage> message, int *errorCode) {
if (message->getContents().size() > 1) {
//TODO
LinphoneCore *lc = message->getChatRoom()->getCore();
char tmp[64];
lc->sal->create_uuid(tmp, sizeof(tmp));
string boundary = tmp;
stringstream multipartMessage;
multipartMessage << "--" << boundary;
for (auto it = message->getContents().begin(); it != message->getContents().end(); it++) {
multipartMessage << "\r\n";
multipartMessage << "Content-Type: " << it->getContentType().asString() << "\r\n\r\n";
multipartMessage << it->getBodyAsString() << "\r\n\r\n";
multipartMessage << "--" << boundary;
}
multipartMessage << "--";
Content newContent;
ContentType newContentType("multipart/mixed");
newContentType.setParameter("boundary=" + boundary);
newContent.setContentType(newContentType);
newContent.setBody(multipartMessage.str());
message->setInternalContent(newContent);
return ChatMessageModifier::Result::Done;
}
return ChatMessageModifier::Result::Skipped;
}
}
ChatMessageModifier::Result MultipartChatMessageModifier::decode (shared_ptr<ChatMessage> message, int *errorCode) {
//TODO
if (false) { // Multipart required
if (message->getInternalContent().getContentType().getType() == "multipart") {
string boundary = message->getInternalContent().getContentType().getParameter();
if (boundary.empty()) {
lError() << "Boundary parameter of content-type not found !";
return ChatMessageModifier::Result::Error;
}
size_t pos = boundary.find("=");
if (pos == string::npos) {
lError() << "Parameter seems invalid: " << boundary;
return ChatMessageModifier::Result::Error;
}
boundary = "--" + boundary.substr(pos + 1);
lInfo() << "Multipart boundary is " << boundary;
const vector<char> body = message->getInternalContent().getBody();
string contentsString(body.begin(), body.end());
pos = contentsString.find(boundary);
if (pos == string::npos) {
lError() << "Boundary not found in body !";
return ChatMessageModifier::Result::Error;
}
size_t start = pos + boundary.length() + 2; // 2 is the size of \r\n
size_t end;
do {
end = contentsString.find(boundary, start);
if (end != string::npos) {
string contentString = contentsString.substr(start, end-start);
size_t contentTypePos = contentString.find(": ") + 2; // 2 is the size of :
size_t endOfLinePos = contentString.find("\r\n");
if (contentTypePos >= endOfLinePos) {
lError() << "Content should start by a 'Content-Type: ' line !";
continue;
}
string contentTypeString = contentString.substr(contentTypePos, endOfLinePos - contentTypePos);
ContentType contentType(contentTypeString);
endOfLinePos += 4; // 4 is two time the size of \r\n
string contentBody = contentString.substr(endOfLinePos, contentString.length() - (endOfLinePos + 4)); // 4 is two time the size of \r\n
Content content;
content.setContentType(contentType);
content.setBody(contentBody);
message->addContent(content);
lInfo() << "Parsed and added content with type " << contentType.asString();
}
start = end + boundary.length() + 2; // 2 is the size of \r\n
} while (end != string::npos);
return ChatMessageModifier::Result::Done;
}
......
......@@ -20,7 +20,7 @@
#include "linphone/utils/utils.h"
#include "object/clonable-object-p.h"
#include "logger/logger.h"
#include "content-type.h"
// =============================================================================
......@@ -33,6 +33,7 @@ class ContentTypePrivate : public ClonableObjectPrivate {
public:
string type;
string subType;
string parameter;
};
// -----------------------------------------------------------------------------
......@@ -52,13 +53,22 @@ ContentType::ContentType (const string &contentType) : ClonableObject(*new Conte
L_D();
size_t pos = contentType.find('/');
size_t posParam = contentType.find("; ");
size_t end = contentType.length();
if (pos == string::npos)
return;
if (setType(contentType.substr(0, pos))) {
if (!setSubType(contentType.substr(pos + 1)))
if (posParam != string::npos) {
end = posParam;
}
if (!setSubType(contentType.substr(pos + 1, end - (pos + 1))))
d->type.clear();
}
if (posParam != string::npos) {
setParameter(contentType.substr(posParam + 2)); // We remove the blankspace after the ;
}
}
ContentType::ContentType (const string &type, const string &subType) : ClonableObject(*new ContentTypePrivate) {
......@@ -70,19 +80,30 @@ ContentType::ContentType (const string &type, const string &subType) : ClonableO
}
}
ContentType::ContentType (const ContentType &src) : ContentType(src.getType(), src.getSubType()) {}
ContentType::ContentType (const string &type, const string &subType, const string &parameter) : ClonableObject(*new ContentTypePrivate) {
L_D();
if (setType(type)) {
if (!setSubType(subType))
d->type.clear();
}
setParameter(parameter);
}
ContentType::ContentType (const ContentType &src) : ContentType(src.getType(), src.getSubType(), src.getParameter()) {}
ContentType &ContentType::operator= (const ContentType &src) {
if (this != &src) {
setType(src.getType());
setSubType(src.getSubType());
setParameter(src.getParameter());
}
return *this;
}
bool ContentType::operator== (const ContentType &contentType) const {
return getType() == contentType.getType() && getSubType() == contentType.getSubType();
return getType() == contentType.getType() && getSubType() == contentType.getSubType() && getParameter() == contentType.getParameter();
}
bool ContentType::operator!= (const ContentType &contentType) const {
......@@ -117,6 +138,16 @@ bool ContentType::setSubType (const string &subType) {
return false;
}
const string &ContentType::getParameter () const {
L_D();
return d->parameter;
}
void ContentType::setParameter (const string &parameter) {
L_D();
d->parameter = parameter;
}
bool ContentType::isValid () const {
L_D();
return !d->type.empty() && !d->subType.empty();
......@@ -124,7 +155,14 @@ bool ContentType::isValid () const {
string ContentType::asString () const {
L_D();
return isValid() ? d->type + "/" + d->subType : "";
if (isValid()) {
string asString = d->type + "/" + d->subType;
if (!d->parameter.empty()) {
asString += "; " + d->parameter;
}
return asString;
}
return "";
}
LINPHONE_END_NAMESPACE
......@@ -32,6 +32,7 @@ class LINPHONE_PUBLIC ContentType : public ClonableObject {
public:
ContentType (const std::string &contentType = "");
ContentType (const std::string &type, const std::string &subType);
ContentType (const std::string &type, const std::string &subType, const std::string &parameter);
ContentType (const ContentType &src);
ContentType &operator= (const ContentType &src);
......@@ -52,6 +53,9 @@ public:
const std::string &getSubType () const;
bool setSubType (const std::string &subType);
const std::string &getParameter () const;
void setParameter (const std::string &parameter);
std::string asString () const;
static const ContentType Cpim;
......
......@@ -382,7 +382,7 @@ static void build_message () {
BC_ASSERT_STRING_EQUAL(strMessage.c_str(), expectedMessage.c_str());
}
static void cpim_chat_message_modifier(void) {
static void cpim_chat_message_modifier_base(bool_t use_multipart) {
LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc");
LpConfig *config = linphone_core_get_config(marie->lc);
......@@ -392,6 +392,12 @@ static void cpim_chat_message_modifier(void) {
shared_ptr<ChatRoom> marieRoom = ObjectFactory::create<BasicChatRoom>(marie->lc, paulineAddress);
shared_ptr<ChatMessage> marieMessage = marieRoom->createMessage("Hello CPIM");
if (use_multipart) {
Content content;
content.setContentType(ContentType::PlainText);
content.setBody("Hello Part 2");
marieMessage->addContent(content);
}
marieRoom->sendMessage(marieMessage);
BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1));
......@@ -407,6 +413,14 @@ static void cpim_chat_message_modifier(void) {
linphone_core_manager_destroy(pauline);
}
static void cpim_chat_message_modifier(void) {
cpim_chat_message_modifier_base(FALSE);
}
static void cpim_chat_message_modifier_with_multipart_body(void) {
cpim_chat_message_modifier_base(TRUE);
}
test_t cpim_tests[] = {
TEST_NO_TAG("Parse minimal CPIM message", parse_minimal_message),
TEST_NO_TAG("Set generic header name", set_generic_header_name),
......@@ -417,7 +431,8 @@ test_t cpim_tests[] = {
TEST_NO_TAG("Parse RFC example", parse_rfc_example),
TEST_NO_TAG("Parse Message with generic header parameters", parse_message_with_generic_header_parameters),
TEST_NO_TAG("Build Message", build_message),
TEST_NO_TAG("CPIM chat message modifier", cpim_chat_message_modifier)
TEST_NO_TAG("CPIM chat message modifier", cpim_chat_message_modifier),
TEST_NO_TAG("CPIM chat message modifier with multipart body", cpim_chat_message_modifier_with_multipart_body),
};
test_suite_t cpim_test_suite = {
......
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