Commit 8a30c727 authored by Sylvain Berfini's avatar Sylvain Berfini 🎩

Improved parameter use in ContentType

parent cf2b6ca2
......@@ -348,23 +348,26 @@ void sal_body_handler_set_subtype(SalBodyHandler *body_handler, const char *subt
belle_sip_header_content_type_set_subtype(content_type, subtype);
}
char * sal_body_handler_get_content_type_parameters(const SalBodyHandler *body_handler) {
const belle_sip_list_t * sal_body_handler_get_content_type_parameters_names(const SalBodyHandler *body_handler) {
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
if (content_type != NULL) {
char buff[2048];
size_t buff_size = sizeof(buff);
size_t offset = 0;
belle_sip_parameters_marshal(BELLE_SIP_PARAMETERS(content_type), buff, buff_size, &offset);
buff[offset]='\0';
return strdup(buff);
return belle_sip_parameters_get_parameter_names(BELLE_SIP_PARAMETERS(content_type));
}
return NULL;
}
void sal_body_handler_set_content_type_parameters(SalBodyHandler *body_handler, const char *params) {
const char * sal_body_handler_get_content_type_parameter(const SalBodyHandler *body_handler, const char *name) {
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
if (content_type != NULL) {
belle_sip_parameters_set(BELLE_SIP_PARAMETERS(content_type), params);
return belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type), name);
}
return NULL;
}
void sal_body_handler_set_content_type_parameter(SalBodyHandler *body_handler, const char *paramName, const char *paramValue) {
belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type"));
if (content_type != NULL) {
belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(content_type), paramName, paramValue);
}
}
......
......@@ -88,6 +88,14 @@ LINPHONE_PUBLIC const char * linphone_content_get_subtype(const LinphoneContent
*/
LINPHONE_PUBLIC void linphone_content_set_subtype(LinphoneContent *content, const char *subtype);
/**
* Adds a parameter to the ContentType header.
* @param[in] content LinphoneContent object.
* @param[in] name the name of the parameter to add.
* @param[in] value the value of the parameter to add.
*/
LINPHONE_PUBLIC void linphone_content_add_content_type_parameter(LinphoneContent *content, const char *name, const char *value);
/**
* Get the content data buffer, usually a string.
* @param[in] content LinphoneContent object.
......
......@@ -99,6 +99,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
content/content.h
content/file-content.h
content/file-transfer-content.h
content/header-param.h
core/core-accessor.h
core/core-listener.h
core/core-p.h
......@@ -223,6 +224,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
content/content.cpp
content/file-content.cpp
content/file-transfer-content.cpp
content/header-param.cpp
core/core-accessor.cpp
core/core-call.cpp
core/core-chat-room.cpp
......
......@@ -24,6 +24,7 @@
#include "content/content.h"
#include "content/content-type.h"
#include "content/header-param.h"
#include "content/content-manager.h"
#include "content/file-content.h"
#include "content/file-transfer-content.h"
......@@ -90,6 +91,12 @@ void linphone_content_set_subtype(LinphoneContent *content, const char *subtype)
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setContentType(ct);
}
void linphone_content_add_content_type_parameter(LinphoneContent *content, const char *name, const char *value) {
LinphonePrivate::ContentType ct = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
ct.addParameter(L_C_TO_STRING(name), L_C_TO_STRING(value));
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setContentType(ct);
}
uint8_t * linphone_content_get_buffer(const LinphoneContent *content) {
return (uint8_t *)linphone_content_get_string_buffer(content);
}
......@@ -235,13 +242,15 @@ static LinphoneContent * linphone_content_new_with_body_handler(SalBodyHandler *
L_SET_CPP_PTR_FROM_C_OBJECT(content, c);
if (body_handler != NULL) {
LinphonePrivate::ContentType ct = c->getContentType();
ct.setType(sal_body_handler_get_type(body_handler));
ct.setSubType(sal_body_handler_get_subtype(body_handler));
ct.setParameter(sal_body_handler_get_content_type_parameters(body_handler));
c->setContentType(ct);
linphone_content_set_type(content, sal_body_handler_get_type(body_handler));
linphone_content_set_subtype(content, sal_body_handler_get_subtype(body_handler));
for (const belle_sip_list_t *params = sal_body_handler_get_content_type_parameters_names(body_handler); params; params = params->next) {
const char *paramName = (const char *)(params->data);
const char *paramValue = sal_body_handler_get_content_type_parameter(body_handler, paramName);
linphone_content_add_content_type_parameter(content, paramName, paramValue);
}
if (!sal_body_handler_is_multipart(body_handler)) {
if (!linphone_content_is_multipart(content)) {
linphone_content_set_string_buffer(content, (char *)sal_body_handler_get_data(body_handler));
} else {
belle_sip_multipart_body_handler_t *mpbh = BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler);
......@@ -302,7 +311,7 @@ SalBodyHandler * sal_body_handler_from_content(const LinphoneContent *content) {
if (contentType.isMultipart()) {
size_t size = linphone_content_get_size(content);
char *buffer = ms_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(content)->getBodyAsUtf8String().c_str());
const char *boundary = L_STRING_TO_C(contentType.getParameter());
const char *boundary = L_STRING_TO_C(contentType.getParameter("boundary").getValue());
belle_sip_multipart_body_handler_t *bh = belle_sip_multipart_body_handler_new_from_buffer(buffer, size, boundary);
body_handler = (SalBodyHandler *)BELLE_SIP_BODY_HANDLER(bh);
} else {
......@@ -323,7 +332,9 @@ SalBodyHandler * sal_body_handler_from_content(const LinphoneContent *content) {
sal_body_handler_set_type(body_handler, contentType.getType().c_str());
sal_body_handler_set_subtype(body_handler, contentType.getSubType().c_str());
sal_body_handler_set_size(body_handler, linphone_content_get_size(content));
sal_body_handler_set_content_type_parameters(body_handler, contentType.getParameter().c_str());
for (const auto &param : contentType.getParameters()) {
sal_body_handler_set_content_type_parameter(body_handler, param.getName().c_str(), param.getValue().c_str());
}
if (content->encoding) sal_body_handler_set_encoding(body_handler, linphone_content_get_encoding(content));
return body_handler;
......
......@@ -636,8 +636,9 @@ const char * sal_body_handler_get_type(const SalBodyHandler *body_handler);
void sal_body_handler_set_type(SalBodyHandler *body_handler, const char *type);
const char * sal_body_handler_get_subtype(const SalBodyHandler *body_handler);
void sal_body_handler_set_subtype(SalBodyHandler *body_handler, const char *subtype);
char * sal_body_handler_get_content_type_parameters(const SalBodyHandler *body_handler);
void sal_body_handler_set_content_type_parameters(SalBodyHandler *body_handler, const char *params);
const belle_sip_list_t * sal_body_handler_get_content_type_parameters_names(const SalBodyHandler *body_handler);
const char * sal_body_handler_get_content_type_parameter(const SalBodyHandler *body_handler, const char *name);
void sal_body_handler_set_content_type_parameter(SalBodyHandler *body_handler, const char *paramName, const char *paramValue);
const char * sal_body_handler_get_encoding(const SalBodyHandler *body_handler);
void sal_body_handler_set_encoding(SalBodyHandler *body_handler, const char *encoding);
void * sal_body_handler_get_data(const SalBodyHandler *body_handler);
......
......@@ -36,6 +36,7 @@
#include "chat/modifier/file-transfer-chat-message-modifier.h"
#include "chat/modifier/multipart-chat-message-modifier.h"
#include "content/file-content.h"
#include "content/header-param.h"
#include "content/content.h"
#include "core/core.h"
#include "core/core-p.h"
......@@ -450,7 +451,7 @@ static void forceUtf8Content (Content &content) {
if (contentType != ContentType::PlainText)
return;
string charset = contentType.getParameter();
string charset = contentType.getParameter("charset").getValue();
if (charset.empty())
return;
......@@ -469,7 +470,7 @@ static void forceUtf8Content (Content &content) {
if (!utf8Body.empty()) {
// TODO: use move operator if possible in the future!
content.setBodyFromUtf8(utf8Body);
contentType.setParameter(string(contentType.getParameter()).replace(begin, end - begin, "UTF-8"));
contentType.addParameter("charset", "UTF-8");
content.setContentType(contentType);
}
}
......
......@@ -24,6 +24,7 @@
#include "chat/chat-message/chat-message.h"
#include "chat/chat-room/chat-room.h"
#include "content/content-type.h"
#include "content/header-param.h"
#include "content/file-transfer-content.h"
#include "logger/logger.h"
#include "core/core.h"
......@@ -60,7 +61,7 @@ ChatMessageModifier::Result MultipartChatMessageModifier::encode (
Content newContent;
ContentType newContentType(ContentType::Multipart);
newContentType.setParameter("boundary=" + boundary);
newContentType.addParameter("boundary", boundary);
newContent.setContentType(newContentType);
newContent.setBody(multipartMessage.str());
message->setInternalContent(newContent);
......@@ -70,7 +71,7 @@ ChatMessageModifier::Result MultipartChatMessageModifier::encode (
ChatMessageModifier::Result MultipartChatMessageModifier::decode (const shared_ptr<ChatMessage> &message, int &errorCode) {
if (message->getInternalContent().getContentType().getType() == "multipart") {
string boundary = message->getInternalContent().getContentType().getParameter();
string boundary = message->getInternalContent().getContentType().getParameter("boundary").getValue();
if (boundary.empty()) {
lError() << "Boundary parameter of content-type not found: " << message->getInternalContent().getContentType().asString();
return ChatMessageModifier::Result::Error;
......
......@@ -112,7 +112,7 @@ Content ContentManager::contentListToMultipart (const list<Content> &contents) {
belle_sip_object_unref(mpbh);
ContentType contentType = ContentType::Multipart;
contentType.setParameter("boundary=" + string(MultipartBoundary));
contentType.addParameter("boundary", string(MultipartBoundary));
content.setContentType(contentType);
return content;
......
......@@ -18,8 +18,10 @@
*/
#include "linphone/utils/utils.h"
#include "linphone/utils/algorithm.h"
#include "content-type.h"
#include "header-param.h"
#include "object/clonable-object-p.h"
// =============================================================================
......@@ -34,7 +36,7 @@ class ContentTypePrivate : public ClonableObjectPrivate {
public:
string type;
string subType;
string parameter;
std::list<HeaderParam> parameters;
};
// -----------------------------------------------------------------------------
......@@ -68,8 +70,15 @@ ContentType::ContentType (const string &contentType) : ClonableObject(*new Conte
d->type.clear();
}
if (posParam != string::npos)
setParameter(Utils::trim(contentType.substr(posParam + 1)));
if (posParam != string::npos) {
string params = contentType.substr(posParam, end);
string token;
while ((pos = params.find(";")) != std::string::npos) {
token = params.substr(0, pos);
addParameter(HeaderParam(token));
params.erase(0, pos + 1);
}
}
}
ContentType::ContentType (const string &type, const string &subType) : ClonableObject(*new ContentTypePrivate) {
......@@ -82,22 +91,34 @@ ContentType::ContentType (const string &type, const string &subType) : ClonableO
ContentType::ContentType (
const string &type,
const string &subType,
const string &parameter
const HeaderParam &parameter
) : ClonableObject(*new ContentTypePrivate) {
L_D();
if (setType(type) && !setSubType(subType))
d->type.clear();
setParameter(parameter);
addParameter(parameter);
}
ContentType::ContentType (const ContentType &other) : ContentType(other.getType(), other.getSubType(), other.getParameter()) {}
ContentType::ContentType (
const string &type,
const string &subType,
const std::list<HeaderParam> &parameters
) : ClonableObject(*new ContentTypePrivate) {
L_D();
if (setType(type) && !setSubType(subType))
d->type.clear();
addParameters(parameters);
}
ContentType::ContentType (const ContentType &other) : ContentType(other.getType(), other.getSubType(), other.getParameters()) {}
ContentType &ContentType::operator= (const ContentType &other) {
if (this != &other) {
setType(other.getType());
setSubType(other.getSubType());
setParameter(other.getParameter());
addParameters(other.getParameters());
}
return *this;
......@@ -106,7 +127,7 @@ ContentType &ContentType::operator= (const ContentType &other) {
bool ContentType::operator== (const ContentType &other) const {
return getType() == other.getType() &&
getSubType() == other.getSubType() &&
getParameter() == other.getParameter();
getParameters() == other.getParameters();
}
bool ContentType::operator!= (const ContentType &other) const {
......@@ -141,14 +162,54 @@ bool ContentType::setSubType (const string &subType) {
return false;
}
const string &ContentType::getParameter () const {
const std::list<HeaderParam> &ContentType::getParameters () const {
L_D();
return d->parameter;
return d->parameters;
}
void ContentType::setParameter (const string &parameter) {
void ContentType::addParameter (const std::string &paramName, const std::string &paramValue) {
addParameter(HeaderParam(paramName, paramValue));
}
void ContentType::addParameter (const HeaderParam &param) {
L_D();
d->parameter = parameter;
removeParameter(param);
d->parameters.push_back(param);
}
void ContentType::addParameters(const std::list<HeaderParam> &params) {
for (auto it = std::begin(params); it!=std::end(params); ++it) {
HeaderParam param = *it;
addParameter(param.getName(), param.getValue());
}
}
void ContentType::removeParameter (const std::string &paramName) {
L_D();
auto it = findParameter(paramName);
if (it != d->parameters.cend())
d->parameters.remove(*it);
}
void ContentType::removeParameter (const HeaderParam &param) {
removeParameter(param.getName());
}
std::list<HeaderParam>::const_iterator ContentType::findParameter (const std::string &paramName) const {
L_D();
return findIf(d->parameters, [&paramName](const HeaderParam &param) {
return param.getName() == paramName;
});
}
const HeaderParam &ContentType::getParameter (const std::string &paramName) const {
L_D();
std::list<HeaderParam>::const_iterator it = findParameter(paramName);
if (it != d->parameters.cend()) {
return *it;
}
return Utils::getEmptyConstRefObject<HeaderParam>();
}
bool ContentType::isEmpty () const {
......@@ -165,8 +226,10 @@ string ContentType::asString () const {
L_D();
if (isValid()) {
string asString = d->type + "/" + d->subType;
if (!d->parameter.empty())
asString += "; " + d->parameter;
for (auto it = std::begin(getParameters()); it!=std::end(getParameters()); ++it) {
HeaderParam param = *it;
asString += param.asString();
}
return asString;
}
return "";
......
......@@ -20,6 +20,8 @@
#ifndef _L_CONTENT_TYPE_H_
#define _L_CONTENT_TYPE_H_
#include <list>
#include "object/clonable-object.h"
// =============================================================================
......@@ -27,12 +29,14 @@
LINPHONE_BEGIN_NAMESPACE
class ContentTypePrivate;
class HeaderParam;
class LINPHONE_PUBLIC ContentType : public ClonableObject {
public:
explicit 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 std::string &type, const std::string &subType, const HeaderParam &parameter);
ContentType (const std::string &type, const std::string &subType, const std::list<HeaderParam> &parameters);
ContentType (const ContentType &other);
ContentType &operator= (const ContentType &other);
......@@ -55,8 +59,14 @@ public:
const std::string &getSubType () const;
bool setSubType (const std::string &subType);
const std::string &getParameter () const;
void setParameter (const std::string &parameter);
const std::list<HeaderParam> &getParameters () const;
void addParameter (const std::string &paramName, const std::string &paramValue);
void addParameter (const HeaderParam &param);
void addParameters(const std::list<HeaderParam> &params);
void removeParameter (const std::string &paramName);
void removeParameter (const HeaderParam &param);
std::list<HeaderParam>::const_iterator findParameter (const std::string &paramName) const;
const HeaderParam &getParameter (const std::string &paramName) const;
std::string asString () const;
......
/*
* header-param.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 "linphone/utils/utils.h"
#include "header-param.h"
#include "object/clonable-object-p.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
class HeaderParamPrivate : public ClonableObjectPrivate {
public:
string name;
string value;
};
// -----------------------------------------------------------------------------
HeaderParam::HeaderParam (const string &param) : ClonableObject(*new HeaderParamPrivate) {
size_t pos = param.find("=");
size_t end = param.length();
if (pos == string::npos)
return;
setName(param.substr(0, pos));
setValue(param.substr(pos + 1, end));
}
HeaderParam::HeaderParam (const string &name, const string &value) : ClonableObject(*new HeaderParamPrivate) {
setName(name);
setValue(value);
}
HeaderParam::HeaderParam (const HeaderParam &other) : HeaderParam(other.getName(), other.getValue()) {}
HeaderParam &HeaderParam::operator= (const HeaderParam &other) {
if (this != &other) {
setName(other.getName());
setValue(other.getValue());
}
return *this;
}
bool HeaderParam::operator== (const HeaderParam &other) const {
return getName() == other.getName() &&
getValue() == other.getValue();
}
bool HeaderParam::operator!= (const HeaderParam &other) const {
return !(*this == other);
}
const string &HeaderParam::getName () const {
L_D();
return d->name;
}
bool HeaderParam::setName (const string &name) {
L_D();
d->name = name;
return true;
}
const string &HeaderParam::getValue () const {
L_D();
return d->value;
}
bool HeaderParam::setValue (const string &value) {
L_D();
d->value = value;
return true;
}
string HeaderParam::asString () const {
L_D();
string asString = ";" + d->name + "=" + d->value;
return asString;
}
LINPHONE_END_NAMESPACE
/*
* header-param.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_HEADER_PARAM_H_
#define _L_HEADER_PARAM_H_
#include "object/clonable-object.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class HeaderParamPrivate;
class LINPHONE_PUBLIC HeaderParam : public ClonableObject {
public:
explicit HeaderParam (const std::string &header = "");
HeaderParam (const std::string &name, const std::string &value);
HeaderParam (const HeaderParam &other);
HeaderParam &operator= (const HeaderParam &other);
bool operator== (const HeaderParam &other) const;
bool operator!= (const HeaderParam &other) const;
// Delete these operators to prevent putting complicated content-type strings
// in the code. Instead define static const HeaderParam objects below.
bool operator== (const std::string &other) const = delete;
bool operator!= (const std::string &other) const = delete;
const std::string &getName () const;
bool setName (const std::string &name);
const std::string &getValue () const;
bool setValue (const std::string &value);
std::string asString () const;
private:
L_DECLARE_PRIVATE(HeaderParam);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_HEADER_PARAM_H_
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