mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-31 10:19:23 +00:00
Simple ChatMessageMultipartModifier created + fixed a few things related to ChatMessages
This commit is contained in:
parent
5dc6b956df
commit
0db6249af5
9 changed files with 171 additions and 26 deletions
|
|
@ -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 ¶meter) : 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 ¶meter) {
|
||||
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 ¶meter);
|
||||
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 ¶meter);
|
||||
|
||||
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 = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue