Source

Target

Commits (11)
Showing with 356 additions and 88 deletions
......@@ -341,6 +341,8 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
if (name_object)
xmlXPathFreeObject(name_object);
bctbx_list_t *parts = linphone_content_get_parts(body);
resource_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/rlmi:list/rlmi:resource/rlmi:instance[@state=\"active\"]/..");
if (resource_object && resource_object->nodesetval) {
for (i = 1; i <= resource_object->nodesetval->nodeNr; i++) {
......@@ -348,7 +350,20 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
linphone_xml_xpath_context_set_node(xml_ctx, xmlXPathNodeSetItem(resource_object->nodesetval, i-1));
cid = linphone_get_xml_text_content(xml_ctx, "./rlmi:instance/@cid");
if (cid) {
presence_part = linphone_content_find_part_by_header(body, "Content-Id", cid);
presence_part = nullptr;
bctbx_list_t *it = parts;
while (it != nullptr)
{
LinphoneContent *content = (LinphoneContent *)it->data;
const char *header = linphone_content_get_custom_header(content, "Content-Id");
if (header && strcmp(header, cid) == 0)
{
presence_part = linphone_content_ref(content);
break;
}
it = bctbx_list_next(it);
}
if (!presence_part) {
ms_warning("rlmi+xml: Cannot find part with Content-Id: %s", cid);
} else {
......@@ -417,6 +432,8 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
}
bctbx_list_free(list_friends_presence_received);
}
bctbx_list_free_with_data(parts, (void (*)(void *))linphone_content_unref);
if (resource_object)
xmlXPathFreeObject(resource_object);
} else {
......
......@@ -31,7 +31,7 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx_csharp.csharp', 'javasphinx', 'swift_domain']
extensions = ['sphinx_csharp.csharp', 'javasphinx']#, 'swift_domain']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
......
......@@ -2496,50 +2496,57 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
}
}
void linphone_core_start (LinphoneCore *lc) {
if (lc->state == LinphoneGlobalOn) {
bctbx_warning("Core is already started, skipping...");
return;
} else if (lc->state == LinphoneGlobalShutdown) {
bctbx_error("Can't start a Core that is stopping, wait for Off state");
return;
} else if (lc->state == LinphoneGlobalOff) {
bctbx_warning("Core was stopped, before starting it again we need to init it");
linphone_core_init(lc, NULL, lc->config, lc->data, NULL, FALSE);
LinphoneStatus linphone_core_start (LinphoneCore *lc) {
try {
if (lc->state == LinphoneGlobalOn) {
bctbx_warning("Core is already started, skipping...");
return -1;
} else if (lc->state == LinphoneGlobalShutdown) {
bctbx_error("Can't start a Core that is stopping, wait for Off state");
return -1;
} else if (lc->state == LinphoneGlobalOff) {
bctbx_warning("Core was stopped, before starting it again we need to init it");
linphone_core_init(lc, NULL, lc->config, lc->data, NULL, FALSE);
// Decrement refs to avoid leaking
lp_config_unref(lc->config);
linphone_core_deactivate_log_serialization_if_needed();
bctbx_uninit_logger();
}
// Decrement refs to avoid leaking
lp_config_unref(lc->config);
linphone_core_deactivate_log_serialization_if_needed();
bctbx_uninit_logger();
}
linphone_core_set_state(lc, LinphoneGlobalStartup, "Starting up");
linphone_core_set_state(lc, LinphoneGlobalStartup, "Starting up");
L_GET_PRIVATE_FROM_C_OBJECT(lc)->init();
L_GET_PRIVATE_FROM_C_OBJECT(lc)->init();
//to give a chance to change uuid before starting
const char* uuid=lp_config_get_string(lc->config,"misc","uuid",NULL);
if (!uuid){
string uuid = lc->sal->createUuid();
lp_config_set_string(lc->config,"misc","uuid",uuid.c_str());
}else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/
lc->sal->setUuid(uuid);
//to give a chance to change uuid before starting
const char* uuid=lp_config_get_string(lc->config,"misc","uuid",NULL);
if (!uuid){
string uuid = lc->sal->createUuid();
lp_config_set_string(lc->config,"misc","uuid",uuid.c_str());
}else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/
lc->sal->setUuid(uuid);
if (!lc->sal->getRootCa().empty()) {
belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, lc->sal->getRootCa().c_str());
belle_http_provider_set_tls_crypto_config(lc->http_provider, lc->http_crypto_config);
}
if (!lc->sal->getRootCa().empty()) {
belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, lc->sal->getRootCa().c_str());
belle_http_provider_set_tls_crypto_config(lc->http_provider, lc->http_crypto_config);
}
getPlatformHelpers(lc)->onLinphoneCoreStart(!!lc->auto_net_state_mon);
getPlatformHelpers(lc)->onLinphoneCoreStart(!!lc->auto_net_state_mon);
linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring");
linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring");
const char *remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
if (remote_provisioning_uri) {
if (linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri) == -1)
linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "Bad URI");
} else {
linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL);
}
const char *remote_provisioning_uri = linphone_core_get_provisioning_uri(lc);
if (remote_provisioning_uri) {
if (linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri) == -1)
linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "Bad URI");
} else {
linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL);
return 0;
} catch (const CorePrivate::DatabaseConnectionFailure &e) {
bctbx_error("%s", e.what());
return -2;
}
}
......
......@@ -169,6 +169,13 @@ LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr);
*/
LINPHONE_PUBLIC int linphone_chat_room_get_history_size(LinphoneChatRoom *cr);
/**
* Returns whether or not a #LinphoneChatRoom has at least one #LinphoneChatMessage or not.
* @param[in] cr The #LinphoneChatRoom object corresponding to the conversation
* @return true if there are no #LinphoneChatMessage, false otherwise.
*/
LINPHONE_PUBLIC bool_t linphone_chat_room_is_empty (LinphoneChatRoom *cr);
/**
* Gets nb_message most recent messages from cr chat room, sorted from oldest to most recent.
* @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which messages should be retrieved
......
......@@ -185,6 +185,14 @@ LINPHONE_PUBLIC void linphone_content_set_name (LinphoneContent *content, const
*/
LINPHONE_PUBLIC bool_t linphone_content_is_multipart (const LinphoneContent *content);
/**
* Get all the parts from a multipart content.
* @param[in] content #LinphoneContent object.
* @return A \bctbx_list{LinphoneContent} \onTheFlyList object holding the part if found, NULL otherwise.
*/
LINPHONE_PUBLIC
bctbx_list_t *linphone_content_get_parts (const LinphoneContent *content);
/**
* Get a part from a multipart content according to its index.
* @param[in] content #LinphoneContent object.
......
......@@ -1039,8 +1039,9 @@ LINPHONE_DEPRECATED LINPHONE_PUBLIC LinphoneCore *linphone_core_new_with_config(
* Must be called only if #LinphoneGlobalState is either Ready of Off. State will changed to Startup, Configuring and then On.
* @ingroup initializing
* @param[in] core The #LinphoneCore object to be started
* @return 0: success, -1: global failure, -2: could not connect database
*/
LINPHONE_PUBLIC void linphone_core_start (LinphoneCore *core);
LINPHONE_PUBLIC LinphoneStatus linphone_core_start(LinphoneCore *lc);
/**
* Stop a #LinphoneCore object after it has been instantiated and started.
......
......@@ -82,6 +82,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
address/address-p.h
address/address.h
address/identity-address.h
address/identity-address-parser.h
c-wrapper/c-wrapper.h
c-wrapper/internal/c-sal.h
c-wrapper/internal/c-tools.h
......@@ -241,6 +242,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
address/address.cpp
address/identity-address.cpp
address/identity-address-parser.cpp
c-wrapper/api/c-address.cpp
c-wrapper/api/c-call-cbs.cpp
c-wrapper/api/c-call-params.cpp
......
/*
* identity-address-parser.cpp
* Copyright (C) 2019 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 <set>
#include <unordered_map>
#include <belr/abnf.h>
#include <belr/grammarbuilder.h>
#include "linphone/utils/utils.h"
#include "logger/logger.h"
#include "object/object-p.h"
#include "identity-address-parser.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
class IdentityAddressParserPrivate : public ObjectPrivate {
public:
shared_ptr<belr::Parser<shared_ptr<IdentityAddress> >> parser;
unordered_map<string, shared_ptr<IdentityAddress >> cache;
};
IdentityAddressParser::IdentityAddressParser () : Singleton(*new IdentityAddressParserPrivate) {
L_D();
const char *identityAddressGrammar =
"address = scheme \":\" [user] \"@\" host [ gruu-parameter ] \r\n"
"scheme = \"sip\" / \"sips\" \r\n"
"user = 1*( alphanum / escaped / \"-\" / \"+\" / \"_\" / \"~\" ) \r\n"
"escaped = \"%\" HEXDIG HEXDIG \r\n"
"host = *( domainlabel \".\" ) toplabel [ \".\" ] \r\n"
"domainlabel = alphanum / (alphanum *( alphanum / ( *(\"-\") alphanum) ) ) \r\n"
"toplabel = ALPHA / (ALPHA *( alphanum / (*(\"-\") alphanum ) ) ) \r\n"
"gruu-parameter = \";gr=\" gruu-value \r\n"
"gruu-value = 1*( alphanum / \"-\" / \"_\" / \":\" ) \r\n"
"alphanum = ALPHA / DIGIT \r\n";
belr::ABNFGrammarBuilder builder;
shared_ptr<belr::Grammar> defaultGrammar = make_shared<belr::Grammar>("");
defaultGrammar->include(make_shared<belr::CoreRules>());
shared_ptr<belr::Grammar> grammar = builder.createFromAbnf(identityAddressGrammar, defaultGrammar);
//shared_ptr<belr::Grammar> grammar = belr::GrammarLoader::get().load(IdentityAddressGrammar);
if (!grammar)
lFatal() << "Unable to load Identity Address grammar.";
d->parser = make_shared<belr::Parser<shared_ptr<IdentityAddress>>>(grammar);
d->parser->setHandler("address", belr::make_fn(make_shared<IdentityAddress>))
->setCollector("scheme", belr::make_sfn(&IdentityAddress::setScheme))
->setCollector("user", belr::make_sfn(&IdentityAddress::setUsername))
->setCollector("host", belr::make_sfn(&IdentityAddress::setDomain))
->setCollector("gruu-value", belr::make_sfn(&IdentityAddress::setGruu));
}
// -----------------------------------------------------------------------------
shared_ptr<IdentityAddress> IdentityAddressParser::parseAddress (const string &input) {
L_D();
auto it = d->cache.find(input);
if (it == d->cache.end()) {
size_t parsedSize;
shared_ptr<IdentityAddress> identityAddress = d->parser->parseInput("Address", input, &parsedSize);
if (!identityAddress) {
lWarning() << "Unable to parse identity address from " << input;
return nullptr;
}
d->cache[input] = identityAddress;
return identityAddress;
} else {
return it->second;
}
}
LINPHONE_END_NAMESPACE
\ No newline at end of file
/*
* identity-address-parser.h
* Copyright (C) 2019 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_IDENTITY_ADDRESS_PARSER_H_
#define _L_IDENTITY_ADDRESS_PARSER_H_
#include "identity-address.h"
#include "object/singleton.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class IdentityAddressParserPrivate;
class IdentityAddressParser : public Singleton<IdentityAddressParser> {
friend class Singleton<IdentityAddressParser>;
public:
std::shared_ptr<IdentityAddress> parseAddress (const std::string &input);
private:
IdentityAddressParser ();
L_DECLARE_PRIVATE(IdentityAddressParser);
L_DISABLE_COPY(IdentityAddressParser);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_IDENTITY_ADDRESS_PARSER_H_
......@@ -20,6 +20,8 @@
#include "linphone/utils/utils.h"
#include "address.h"
#include "identity-address-parser.h"
#include "c-wrapper/c-wrapper.h"
#include "identity-address.h"
#include "logger/logger.h"
......@@ -45,12 +47,20 @@ public:
IdentityAddress::IdentityAddress (const string &address) : ClonableObject(*new IdentityAddressPrivate) {
L_D();
Address tmpAddress(address);
if (tmpAddress.isValid() && ((tmpAddress.getScheme() == "sip") || (tmpAddress.getScheme() == "sips"))) {
d->scheme = tmpAddress.getScheme();
d->username = tmpAddress.getUsername();
d->domain = tmpAddress.getDomain();
d->gruu = tmpAddress.getUriParamValue("gr");
shared_ptr<IdentityAddress> parsedAddress = IdentityAddressParser::getInstance()->parseAddress(address);
if (parsedAddress != nullptr) {
d->scheme = parsedAddress->getScheme();
d->username = parsedAddress->getUsername();
d->domain = parsedAddress->getDomain();
d->gruu = parsedAddress->getGruu();
} else {
Address tmpAddress(address);
if (tmpAddress.isValid() && ((tmpAddress.getScheme() == "sip") || (tmpAddress.getScheme() == "sips"))) {
d->scheme = tmpAddress.getScheme();
d->username = tmpAddress.getUsername();
d->domain = tmpAddress.getDomain();
d->gruu = tmpAddress.getUriParamValue("gr");
}
}
}
......@@ -71,6 +81,10 @@ IdentityAddress::IdentityAddress (const IdentityAddress &other) : ClonableObject
d->gruu = other.getGruu();
}
IdentityAddress::IdentityAddress () : ClonableObject(*new IdentityAddressPrivate) {
}
IdentityAddress &IdentityAddress::operator= (const IdentityAddress &other) {
L_D();
if (this != &other) {
......@@ -115,15 +129,19 @@ const string &IdentityAddress::getScheme () const {
return d->scheme;
}
void IdentityAddress::setScheme (const string &scheme) {
L_D();
d->scheme = scheme;
}
const string &IdentityAddress::getUsername () const {
L_D();
return d->username;
}
bool IdentityAddress::setUsername (const string &username) {
void IdentityAddress::setUsername (const string &username) {
L_D();
d->username = username;
return true;
}
const string &IdentityAddress::getDomain () const {
......@@ -131,10 +149,9 @@ const string &IdentityAddress::getDomain () const {
return d->domain;
}
bool IdentityAddress::setDomain (const string &domain) {
void IdentityAddress::setDomain (const string &domain) {
L_D();
d->domain = domain;
return true;
}
bool IdentityAddress::hasGruu () const {
......@@ -147,10 +164,9 @@ const string &IdentityAddress::getGruu () const {
return d->gruu;
}
bool IdentityAddress::setGruu (const string &gruu) {
void IdentityAddress::setGruu (const string &gruu) {
L_D();
d->gruu = gruu;
return true;
}
IdentityAddress IdentityAddress::getAddressWithoutGruu () const {
......
......@@ -33,9 +33,10 @@ class IdentityAddressPrivate;
class LINPHONE_PUBLIC IdentityAddress : public ClonableObject {
public:
explicit IdentityAddress (const std::string &address = "");
explicit IdentityAddress (const std::string &address);
IdentityAddress (const Address &address);
IdentityAddress (const IdentityAddress &other);
IdentityAddress ();
~IdentityAddress () = default;
IdentityAddress *clone () const override {
......@@ -52,16 +53,17 @@ public:
bool isValid () const;
const std::string &getScheme () const;
void setScheme (const std::string &scheme);
const std::string &getUsername () const;
bool setUsername (const std::string &username);
void setUsername (const std::string &username);
const std::string &getDomain () const;
bool setDomain (const std::string &domain);
void setDomain (const std::string &domain);
bool hasGruu () const;
const std::string &getGruu () const;
bool setGruu (const std::string &gruu);
void setGruu (const std::string &gruu);
IdentityAddress getAddressWithoutGruu () const;
......
......@@ -208,6 +208,10 @@ int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) {
return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatMessageCount();
}
bool_t linphone_chat_room_is_empty (LinphoneChatRoom *cr) {
return (bool_t)L_GET_CPP_PTR_FROM_C_OBJECT(cr)->isEmpty();
}
void linphone_chat_room_delete_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
shared_ptr<LinphonePrivate::EventLog> event = LinphonePrivate::MainDb::getEventFromKey(
L_GET_PRIVATE_FROM_C_OBJECT(msg)->dbKey
......
......@@ -42,6 +42,8 @@ L_DECLARE_C_CLONABLE_OBJECT_IMPL_WITH_XTORS(Content,
void *cryptoContext; // Used to encrypt file for RCS file transfer.
mutable size_t size;
bool_t is_dirty = FALSE;
SalBodyHandler *body_handler;
struct Cache {
string name;
......@@ -49,6 +51,7 @@ L_DECLARE_C_CLONABLE_OBJECT_IMPL_WITH_XTORS(Content,
string subtype;
string buffer;
string file_path;
string header_value;
} mutable cache;
)
......@@ -58,12 +61,14 @@ static void _linphone_content_constructor (LinphoneContent *content) {
static void _linphone_content_destructor (LinphoneContent *content) {
content->cache.~Cache();
if (content->body_handler) sal_body_handler_unref(content->body_handler);
}
static void _linphone_content_c_clone (LinphoneContent *dest, const LinphoneContent *src) {
new(&dest->cache) LinphoneContent::Cache();
dest->size = src->size;
dest->cache = src->cache;
if (!src->is_dirty && src->body_handler) dest->body_handler = sal_body_handler_ref(src->body_handler);
}
// =============================================================================
......@@ -122,6 +127,7 @@ const uint8_t *linphone_content_get_buffer (const LinphoneContent *content) {
}
void linphone_content_set_buffer (LinphoneContent *content, const uint8_t *buffer, size_t size) {
content->is_dirty = TRUE;
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setBody(buffer, size);
}
......@@ -131,6 +137,7 @@ const char *linphone_content_get_string_buffer (const LinphoneContent *content)
}
void linphone_content_set_string_buffer (LinphoneContent *content, const char *buffer) {
content->is_dirty = TRUE;
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setBodyFromUtf8(L_C_TO_STRING(buffer));
}
......@@ -188,12 +195,47 @@ bool_t linphone_content_is_multipart (const LinphoneContent *content) {
return L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType().isMultipart();
}
bctbx_list_t *linphone_content_get_parts (const LinphoneContent *content) {
bctbx_list_t *parts = nullptr;
SalBodyHandler *bodyHandler;
if (!content->is_dirty && content->body_handler) {
bodyHandler = sal_body_handler_ref(content->body_handler);
} else {
bodyHandler = sal_body_handler_from_content(content);
}
if (!sal_body_handler_is_multipart(bodyHandler)) {
sal_body_handler_unref(bodyHandler);
return parts;
}
const bctbx_list_t *sal_parts = sal_body_handler_get_parts(bodyHandler);
bctbx_list_t *it = (bctbx_list_t *)sal_parts;
while (it != nullptr) {
SalBodyHandler *bh = (SalBodyHandler *)it->data;
LinphoneContent *part = linphone_content_from_sal_body_handler(bh);
parts = bctbx_list_append(parts, linphone_content_ref(part));
linphone_content_unref(part);
it = bctbx_list_next(it);
}
sal_body_handler_unref(bodyHandler);
return parts;
}
LinphoneContent *linphone_content_get_part (const LinphoneContent *content, int idx) {
SalBodyHandler *bodyHandler = sal_body_handler_from_content(content);
SalBodyHandler *bodyHandler;
if (!content->is_dirty && content->body_handler) {
bodyHandler = sal_body_handler_ref(content->body_handler);
} else {
bodyHandler = sal_body_handler_from_content(content);
}
if (!sal_body_handler_is_multipart(bodyHandler)) {
sal_body_handler_unref(bodyHandler);
return nullptr;
}
SalBodyHandler *partBodyHandler = sal_body_handler_get_part(bodyHandler, idx);
LinphoneContent *result = linphone_content_from_sal_body_handler(partBodyHandler);
sal_body_handler_unref(bodyHandler);
......@@ -201,11 +243,18 @@ LinphoneContent *linphone_content_get_part (const LinphoneContent *content, int
}
LinphoneContent *linphone_content_find_part_by_header (const LinphoneContent *content, const char *headerName, const char *headerValue) {
SalBodyHandler *bodyHandler = sal_body_handler_from_content(content);
SalBodyHandler *bodyHandler;
if (!content->is_dirty && content->body_handler) {
bodyHandler = sal_body_handler_ref(content->body_handler);
} else {
bodyHandler = sal_body_handler_from_content(content);
}
if (!sal_body_handler_is_multipart(bodyHandler)) {
sal_body_handler_unref(bodyHandler);
return nullptr;
}
SalBodyHandler *partBodyHandler = sal_body_handler_find_part_by_header(bodyHandler, headerName, headerValue);
LinphoneContent *result = linphone_content_from_sal_body_handler(partBodyHandler);
sal_body_handler_unref(bodyHandler);
......@@ -213,10 +262,16 @@ LinphoneContent *linphone_content_find_part_by_header (const LinphoneContent *co
}
const char *linphone_content_get_custom_header (const LinphoneContent *content, const char *headerName) {
SalBodyHandler *bodyHandler = sal_body_handler_from_content(content);
const char *header = sal_body_handler_get_header(bodyHandler, headerName);
SalBodyHandler *bodyHandler;
if (!content->is_dirty && content->body_handler) {
bodyHandler = sal_body_handler_ref(content->body_handler);
} else {
bodyHandler = sal_body_handler_from_content(content);
}
content->cache.header_value = L_C_TO_STRING(sal_body_handler_get_header(bodyHandler, headerName));
sal_body_handler_unref(bodyHandler);
return header;
return content->cache.header_value.c_str();
}
const char *linphone_content_get_key (const LinphoneContent *content) {
......@@ -287,10 +342,13 @@ static LinphoneContent *linphone_content_new_with_body_handler (const SalBodyHan
content->cryptoContext = nullptr;
LinphonePrivate::Content *c = new LinphonePrivate::Content();
L_SET_CPP_PTR_FROM_C_OBJECT(content, c);
content->body_handler = nullptr;
if (!bodyHandler)
return content;
content->body_handler = sal_body_handler_ref((SalBodyHandler *)bodyHandler);
linphone_content_set_type(content, sal_body_handler_get_type(bodyHandler));
linphone_content_set_subtype(content, sal_body_handler_get_subtype(bodyHandler));
for (const belle_sip_list_t *params = sal_body_handler_get_content_type_parameters_names(bodyHandler); params; params = params->next) {
......@@ -349,6 +407,9 @@ SalBodyHandler *sal_body_handler_from_content (const LinphoneContent *content, b
if (!content)
return nullptr;
if (!content->is_dirty && content->body_handler)
return sal_body_handler_ref(content->body_handler);
SalBodyHandler *bodyHandler;
LinphonePrivate::ContentType contentType = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
if (contentType.isMultipart() && parseMultipart) {
......
......@@ -356,7 +356,7 @@ void ChatMessagePrivate::setExternalBodyUrl (const string &url) {
const ContentType &ChatMessagePrivate::getContentType () const {
loadContentsFromDatabase();
if (direction == ChatMessage::Direction::Incoming) {
if (contents.size() > 0) {
if (!contents.empty()) {
Content *content = contents.front();
cContentType = content->getContentType();
} else {
......@@ -366,7 +366,7 @@ const ContentType &ChatMessagePrivate::getContentType () const {
if (internalContent.getContentType().isValid()) {
cContentType = internalContent.getContentType();
} else {
if (contents.size() > 0) {
if (!contents.empty()) {
Content *content = contents.front();
cContentType = content->getContentType();
}
......@@ -377,14 +377,14 @@ const ContentType &ChatMessagePrivate::getContentType () const {
void ChatMessagePrivate::setContentType (const ContentType &contentType) {
loadContentsFromDatabase();
if (contents.size() > 0 && internalContent.getContentType().isEmpty() && internalContent.isEmpty()) {
if (!contents.empty() && internalContent.getContentType().isEmpty() && internalContent.isEmpty()) {
internalContent.setBody(contents.front()->getBody());
}
internalContent.setContentType(contentType);
if ((currentSendStep &ChatMessagePrivate::Step::Started) != ChatMessagePrivate::Step::Started) {
// if not started yet the sending also alter the first content
if (contents.size() > 0)
if (!contents.empty())
contents.front()->setContentType(contentType);
}
}
......@@ -394,7 +394,7 @@ const string &ChatMessagePrivate::getText () const {
if (direction == ChatMessage::Direction::Incoming) {
if (hasTextContent()) {
cText = getTextContent()->getBodyAsString();
} else if (contents.size() > 0) {
} else if (!contents.empty()) {
Content *content = contents.front();
cText = content->getBodyAsString();
} else {
......@@ -404,7 +404,7 @@ const string &ChatMessagePrivate::getText () const {
if (!internalContent.isEmpty()) {
cText = internalContent.getBodyAsString();
} else {
if (contents.size() > 0) {
if (!contents.empty()) {
Content *content = contents.front();
cText = content->getBodyAsString();
}
......@@ -415,14 +415,14 @@ const string &ChatMessagePrivate::getText () const {
void ChatMessagePrivate::setText (const string &text) {
loadContentsFromDatabase();
if (contents.size() > 0 && internalContent.getContentType().isEmpty() && internalContent.isEmpty()) {
if (!contents.empty() && internalContent.getContentType().isEmpty() && internalContent.isEmpty()) {
internalContent.setContentType(contents.front()->getContentType());
}
internalContent.setBody(text);
if ((currentSendStep &ChatMessagePrivate::Step::Started) != ChatMessagePrivate::Step::Started) {
// if not started yet the sending also alter the first content
if (contents.size() > 0)
if (!contents.empty())
contents.front()->setBody(text);
}
}
......@@ -648,7 +648,7 @@ LinphoneReason ChatMessagePrivate::receive () {
q->getChatRoom()->getPrivate()->removeTransientChatMessage(q->getSharedFromThis());
}
if (contents.size() == 0) {
if (contents.empty()) {
// All previous modifiers only altered the internal content, let's fill the content list
contents.push_back(new Content(internalContent));
}
......@@ -868,7 +868,7 @@ void ChatMessagePrivate::send () {
// ---------------------------------------
if (internalContent.isEmpty()) {
if (contents.size() > 0) {
if (!contents.empty()) {
internalContent = *(contents.front());
} else if (externalBodyUrl.empty()) { // When using external body url, there is no content
lError() << "Trying to send a message without any content !";
......
......@@ -47,7 +47,7 @@ public:
virtual void addTransientEvent (const std::shared_ptr<EventLog> &eventLog) = 0;
virtual void removeTransientEvent (const std::shared_ptr<EventLog> &eventLog) = 0;
virtual void sendDeliveryNotifications () = 0;
virtual void sendDeliveryNotifications (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
virtual void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
virtual void notifyUndecryptableChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
......
......@@ -81,7 +81,7 @@ public:
virtual void deleteHistory () = 0;
virtual std::shared_ptr<ChatMessage> getLastChatMessageInHistory () const = 0;
virtual bool isEmpty () const = 0;
virtual int getChatMessageCount () const = 0;
virtual int getUnreadChatMessageCount () const = 0;
......
......@@ -75,7 +75,7 @@ public:
void sendDeliveryErrorNotification (const std::shared_ptr<ChatMessage> &chatMessage, LinphoneReason reason);
void sendDeliveryNotification (const std::shared_ptr<ChatMessage> &chatMessage);
void sendDeliveryNotifications () override;
void sendDeliveryNotifications (const std::shared_ptr<ChatMessage> &chatMessage) override;
void sendDisplayNotification (const std::shared_ptr<ChatMessage> &chatMessage);
void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override;
......
......@@ -186,18 +186,11 @@ void ChatRoomPrivate::sendDeliveryNotification (const shared_ptr<ChatMessage> &c
}
}
void ChatRoomPrivate::sendDeliveryNotifications () {
L_Q();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) {
auto chatMessages = q->getCore()->getPrivate()->mainDb->findChatMessagesToBeNotifiedAsDelivered(q->getConferenceId());
for (const auto &chatMessage : chatMessages) {
ChatMessagePrivate *dChatMessage = chatMessage->getPrivate();
if (dChatMessage->getPositiveDeliveryNotificationRequired()) {
dChatMessage->setPositiveDeliveryNotificationRequired(false);
imdnHandler->notifyDelivery(chatMessage);
}
}
void ChatRoomPrivate::sendDeliveryNotifications (const std::shared_ptr<ChatMessage> &chatMessage) {
ChatMessagePrivate *dChatMessage = chatMessage->getPrivate();
if (dChatMessage->getPositiveDeliveryNotificationRequired()) {
dChatMessage->setPositiveDeliveryNotificationRequired(false);
imdnHandler->notifyDelivery(chatMessage);
}
}
......@@ -471,6 +464,10 @@ shared_ptr<ChatMessage> ChatRoom::getLastChatMessageInHistory () const {
return getCore()->getPrivate()->mainDb->getLastChatMessage(getConferenceId());
}
bool ChatRoom::isEmpty () const {
return getCore()->getPrivate()->mainDb->getLastChatMessage(getConferenceId()) == nullptr;
}
int ChatRoom::getChatMessageCount () const {
return getCore()->getPrivate()->mainDb->getChatMessageCount(getConferenceId());
}
......
......@@ -61,7 +61,7 @@ public:
void deleteHistory () override;
std::shared_ptr<ChatMessage> getLastChatMessageInHistory () const override;
bool isEmpty () const override;
int getChatMessageCount () const override;
int getUnreadChatMessageCount () const override;
......
......@@ -65,8 +65,8 @@ public:
chatRoom->getPrivate()->removeTransientChatMessage(message);
}
inline void sendDeliveryNotifications () override {
chatRoom->getPrivate()->sendDeliveryNotifications();
inline void sendDeliveryNotifications (const std::shared_ptr<ChatMessage> &chatMessage) override {
chatRoom->getPrivate()->sendDeliveryNotifications(chatMessage);
}
inline void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override {
......