Source

Target

Commits (12)
Showing with 309 additions and 35 deletions
...@@ -787,6 +787,7 @@ static void _create_account_cb_custom(LinphoneXmlRpcRequest *request) { ...@@ -787,6 +787,7 @@ static void _create_account_cb_custom(LinphoneXmlRpcRequest *request) {
: (strcmp(resp, "ERROR_MAX_SMS_EXCEEDED") == 0) ? LinphoneAccountCreatorStatusPhoneNumberOverused : (strcmp(resp, "ERROR_MAX_SMS_EXCEEDED") == 0) ? LinphoneAccountCreatorStatusPhoneNumberOverused
: (strcmp(resp, "ERROR_ACCOUNT_ALREADY_IN_USE") == 0) ? LinphoneAccountCreatorStatusAccountExist : (strcmp(resp, "ERROR_ACCOUNT_ALREADY_IN_USE") == 0) ? LinphoneAccountCreatorStatusAccountExist
: (strcmp(resp, "ERROR_ALIAS_ALREADY_IN_USE") == 0) ? LinphoneAccountCreatorStatusAccountExistWithAlias : (strcmp(resp, "ERROR_ALIAS_ALREADY_IN_USE") == 0) ? LinphoneAccountCreatorStatusAccountExistWithAlias
: (strcmp(resp, "ERROR_ALGO_NOT_SUPPORTED") == 0) ? LinphoneAccountCreatorStatusAlgoNotSupported
: LinphoneAccountCreatorStatusAccountNotCreated; : LinphoneAccountCreatorStatusAccountNotCreated;
} }
if (creator->cbs->create_account_response_cb != NULL) { if (creator->cbs->create_account_response_cb != NULL) {
...@@ -872,6 +873,7 @@ static void _delete_linphone_account_response_cb(LinphoneXmlRpcRequest *request) ...@@ -872,6 +873,7 @@ static void _delete_linphone_account_response_cb(LinphoneXmlRpcRequest *request)
status = (strcmp(resp, "OK") == 0) ? LinphoneAccountCreatorStatusAccountCreated status = (strcmp(resp, "OK") == 0) ? LinphoneAccountCreatorStatusAccountCreated
: (strcmp(resp, "ERROR_USERNAME_PARAMETER_NOT_FOUND") == 0) ? LinphoneAccountCreatorStatusMissingArguments : (strcmp(resp, "ERROR_USERNAME_PARAMETER_NOT_FOUND") == 0) ? LinphoneAccountCreatorStatusMissingArguments
: (strcmp(resp, "ERROR_ACCOUNT_DOESNT_EXIST") == 0) ? LinphoneAccountCreatorStatusAccountNotExist : (strcmp(resp, "ERROR_ACCOUNT_DOESNT_EXIST") == 0) ? LinphoneAccountCreatorStatusAccountNotExist
: (strcmp(resp, "ERROR_ALGO_NOT_SUPPORTED") == 0) ? LinphoneAccountCreatorStatusAlgoNotSupported
: (strstr(resp, "ERROR_") == 0) ? LinphoneAccountCreatorStatusRequestFailed : (strstr(resp, "ERROR_") == 0) ? LinphoneAccountCreatorStatusRequestFailed
: LinphoneAccountCreatorStatusAccountNotCreated; : LinphoneAccountCreatorStatusAccountNotCreated;
} }
...@@ -919,6 +921,8 @@ static void _activate_account_cb_custom(LinphoneXmlRpcRequest *request) { ...@@ -919,6 +921,8 @@ static void _activate_account_cb_custom(LinphoneXmlRpcRequest *request) {
status = LinphoneAccountCreatorStatusAccountAlreadyActivated; status = LinphoneAccountCreatorStatusAccountAlreadyActivated;
} else if (strcmp(resp, "ERROR_KEY_DOESNT_MATCH") == 0) { } else if (strcmp(resp, "ERROR_KEY_DOESNT_MATCH") == 0) {
status = LinphoneAccountCreatorStatusWrongActivationCode; status = LinphoneAccountCreatorStatusWrongActivationCode;
} else if (strcmp(resp, "ERROR_ALGO_NOT_SUPPORTED") == 0) {
status = LinphoneAccountCreatorStatusAlgoNotSupported;
} else if (strstr(resp, "ERROR_") == resp) { } else if (strstr(resp, "ERROR_") == resp) {
status = LinphoneAccountCreatorStatusAccountNotActivated; status = LinphoneAccountCreatorStatusAccountNotActivated;
} else { } else {
...@@ -1003,6 +1007,8 @@ static void get_linphone_confirmation_key_response_cb(LinphoneXmlRpcRequest *req ...@@ -1003,6 +1007,8 @@ static void get_linphone_confirmation_key_response_cb(LinphoneXmlRpcRequest *req
status = LinphoneAccountCreatorStatusMissingArguments; status = LinphoneAccountCreatorStatusMissingArguments;
} else if (strcmp(resp, "ERROR_ACCOUNT_DOESNT_EXIST") == 0) { } else if (strcmp(resp, "ERROR_ACCOUNT_DOESNT_EXIST") == 0) {
status = LinphoneAccountCreatorStatusAccountNotExist; status = LinphoneAccountCreatorStatusAccountNotExist;
} else if (strcmp(resp, "ERROR_ALGO_NOT_SUPPORTED") == 0) {
status = LinphoneAccountCreatorStatusAlgoNotSupported;
} else if (strstr(resp, "ERROR_") == resp) { } else if (strstr(resp, "ERROR_") == resp) {
status = LinphoneAccountCreatorStatusRequestFailed; status = LinphoneAccountCreatorStatusRequestFailed;
} else { } else {
...@@ -1337,6 +1343,8 @@ static void _password_updated_cb_custom(LinphoneXmlRpcRequest *request) { ...@@ -1337,6 +1343,8 @@ static void _password_updated_cb_custom(LinphoneXmlRpcRequest *request) {
if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) { if (linphone_xml_rpc_request_get_status(request) == LinphoneXmlRpcStatusOk) {
if (strcmp(resp, "OK") == 0) { if (strcmp(resp, "OK") == 0) {
status = LinphoneAccountCreatorStatusRequestOk; status = LinphoneAccountCreatorStatusRequestOk;
} else if (strcmp(resp, "ERROR_ALGO_NOT_SUPPORTED") == 0) {
status = LinphoneAccountCreatorStatusAlgoNotSupported;
} else if (strcmp(resp, "ERROR_PASSWORD_DOESNT_MATCH") == 0) { } else if (strcmp(resp, "ERROR_PASSWORD_DOESNT_MATCH") == 0) {
status = LinphoneAccountCreatorStatusAccountNotExist; status = LinphoneAccountCreatorStatusAccountNotExist;
} else { } else {
......
...@@ -341,6 +341,8 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList ...@@ -341,6 +341,8 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
if (name_object) if (name_object)
xmlXPathFreeObject(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\"]/.."); 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) { if (resource_object && resource_object->nodesetval) {
for (i = 1; i <= resource_object->nodesetval->nodeNr; i++) { for (i = 1; i <= resource_object->nodesetval->nodeNr; i++) {
...@@ -348,7 +350,20 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList ...@@ -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)); 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"); cid = linphone_get_xml_text_content(xml_ctx, "./rlmi:instance/@cid");
if (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) { if (!presence_part) {
ms_warning("rlmi+xml: Cannot find part with Content-Id: %s", cid); ms_warning("rlmi+xml: Cannot find part with Content-Id: %s", cid);
} else { } else {
...@@ -417,6 +432,8 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList ...@@ -417,6 +432,8 @@ static void linphone_friend_list_parse_multipart_related_body(LinphoneFriendList
} }
bctbx_list_free(list_friends_presence_received); bctbx_list_free(list_friends_presence_received);
} }
bctbx_list_free_with_data(parts, (void (*)(void *))linphone_content_unref);
if (resource_object) if (resource_object)
xmlXPathFreeObject(resource_object); xmlXPathFreeObject(resource_object);
} else { } else {
......
...@@ -169,6 +169,13 @@ LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr); ...@@ -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); 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. * 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 * @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 ...@@ -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); 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. * Get a part from a multipart content according to its index.
* @param[in] content #LinphoneContent object. * @param[in] content #LinphoneContent object.
......
...@@ -5998,6 +5998,15 @@ LINPHONE_PUBLIC LinphoneXmlRpcSession * linphone_core_create_xml_rpc_session(Lin ...@@ -5998,6 +5998,15 @@ LINPHONE_PUBLIC LinphoneXmlRpcSession * linphone_core_create_xml_rpc_session(Lin
**/ **/
LINPHONE_PUBLIC void linphone_core_load_config_from_xml(LinphoneCore *lc, const char * xml_uri); LINPHONE_PUBLIC void linphone_core_load_config_from_xml(LinphoneCore *lc, const char * xml_uri);
/**
* Call this method when you receive a push notification.
* It will ensure the proxy configs are correctly registered to the proxy server,
* so the call or the message will be correctly delivered.
* @param[in] lc The #LinphoneCore
* @ingroup misc
**/
LINPHONE_PUBLIC void linphone_core_ensure_registered(LinphoneCore *lc);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -183,6 +183,7 @@ typedef enum _LinphoneAccountCreatorStatus { ...@@ -183,6 +183,7 @@ typedef enum _LinphoneAccountCreatorStatus {
LinphoneAccountCreatorStatusPhoneNumberInvalid, /**< Error cannot send SMS */ LinphoneAccountCreatorStatusPhoneNumberInvalid, /**< Error cannot send SMS */
LinphoneAccountCreatorStatusWrongActivationCode, /**< Error key doesn't match */ LinphoneAccountCreatorStatusWrongActivationCode, /**< Error key doesn't match */
LinphoneAccountCreatorStatusPhoneNumberOverused, /**< Error too many SMS sent */ LinphoneAccountCreatorStatusPhoneNumberOverused, /**< Error too many SMS sent */
LinphoneAccountCreatorStatusAlgoNotSupported, /** < Error algo isn't MD5 or SHA-256 */
} LinphoneAccountCreatorStatus; } LinphoneAccountCreatorStatus;
/** /**
......
...@@ -27,6 +27,7 @@ install(FILES rootca.pem ...@@ -27,6 +27,7 @@ install(FILES rootca.pem
set(GRAMMAR_FILES set(GRAMMAR_FILES
cpim_grammar cpim_grammar
identity_grammar
) )
install(FILES ${GRAMMAR_FILES} install(FILES ${GRAMMAR_FILES}
......
File added
...@@ -82,6 +82,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES ...@@ -82,6 +82,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
address/address-p.h address/address-p.h
address/address.h address/address.h
address/identity-address.h address/identity-address.h
address/identity-address-parser.h
c-wrapper/c-wrapper.h c-wrapper/c-wrapper.h
c-wrapper/internal/c-sal.h c-wrapper/internal/c-sal.h
c-wrapper/internal/c-tools.h c-wrapper/internal/c-tools.h
...@@ -241,6 +242,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES ...@@ -241,6 +242,7 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
set(LINPHONE_CXX_OBJECTS_SOURCE_FILES set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
address/address.cpp address/address.cpp
address/identity-address.cpp address/identity-address.cpp
address/identity-address-parser.cpp
c-wrapper/api/c-address.cpp c-wrapper/api/c-address.cpp
c-wrapper/api/c-call-cbs.cpp c-wrapper/api/c-call-cbs.cpp
c-wrapper/api/c-call-params.cpp c-wrapper/api/c-call-params.cpp
...@@ -434,6 +436,7 @@ endif() ...@@ -434,6 +436,7 @@ endif()
if(ENABLE_SHARED) if(ENABLE_SHARED)
set(LINPHONE_RESOURCES set(LINPHONE_RESOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/../share/cpim_grammar" "${CMAKE_CURRENT_SOURCE_DIR}/../share/cpim_grammar"
"${CMAKE_CURRENT_SOURCE_DIR}/../share/identity_grammar"
"${CMAKE_CURRENT_SOURCE_DIR}/../share/rootca.pem" "${CMAKE_CURRENT_SOURCE_DIR}/../share/rootca.pem"
"${CMAKE_CURRENT_SOURCE_DIR}/../share/ringback.wav" "${CMAKE_CURRENT_SOURCE_DIR}/../share/ringback.wav"
"${CMAKE_CURRENT_SOURCE_DIR}/../share/Modules" "${CMAKE_CURRENT_SOURCE_DIR}/../share/Modules"
......
/*
* 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
namespace {
string IdentityGrammar("identity_grammar");
}
// -----------------------------------------------------------------------------
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();
shared_ptr<belr::Grammar> grammar = belr::GrammarLoader::get().load(IdentityGrammar);
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 @@ ...@@ -20,6 +20,8 @@
#include "linphone/utils/utils.h" #include "linphone/utils/utils.h"
#include "address.h" #include "address.h"
#include "identity-address-parser.h"
#include "c-wrapper/c-wrapper.h" #include "c-wrapper/c-wrapper.h"
#include "identity-address.h" #include "identity-address.h"
#include "logger/logger.h" #include "logger/logger.h"
...@@ -45,12 +47,20 @@ public: ...@@ -45,12 +47,20 @@ public:
IdentityAddress::IdentityAddress (const string &address) : ClonableObject(*new IdentityAddressPrivate) { IdentityAddress::IdentityAddress (const string &address) : ClonableObject(*new IdentityAddressPrivate) {
L_D(); L_D();
Address tmpAddress(address); shared_ptr<IdentityAddress> parsedAddress = IdentityAddressParser::getInstance()->parseAddress(address);
if (tmpAddress.isValid() && ((tmpAddress.getScheme() == "sip") || (tmpAddress.getScheme() == "sips"))) { if (parsedAddress != nullptr) {
d->scheme = tmpAddress.getScheme(); d->scheme = parsedAddress->getScheme();
d->username = tmpAddress.getUsername(); d->username = parsedAddress->getUsername();
d->domain = tmpAddress.getDomain(); d->domain = parsedAddress->getDomain();
d->gruu = tmpAddress.getUriParamValue("gr"); 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 ...@@ -71,6 +81,10 @@ IdentityAddress::IdentityAddress (const IdentityAddress &other) : ClonableObject
d->gruu = other.getGruu(); d->gruu = other.getGruu();
} }
IdentityAddress::IdentityAddress () : ClonableObject(*new IdentityAddressPrivate) {
}
IdentityAddress &IdentityAddress::operator= (const IdentityAddress &other) { IdentityAddress &IdentityAddress::operator= (const IdentityAddress &other) {
L_D(); L_D();
if (this != &other) { if (this != &other) {
...@@ -115,15 +129,19 @@ const string &IdentityAddress::getScheme () const { ...@@ -115,15 +129,19 @@ const string &IdentityAddress::getScheme () const {
return d->scheme; return d->scheme;
} }
void IdentityAddress::setScheme (const string &scheme) {
L_D();
d->scheme = scheme;
}
const string &IdentityAddress::getUsername () const { const string &IdentityAddress::getUsername () const {
L_D(); L_D();
return d->username; return d->username;
} }
bool IdentityAddress::setUsername (const string &username) { void IdentityAddress::setUsername (const string &username) {
L_D(); L_D();
d->username = username; d->username = username;
return true;
} }
const string &IdentityAddress::getDomain () const { const string &IdentityAddress::getDomain () const {
...@@ -131,10 +149,9 @@ const string &IdentityAddress::getDomain () const { ...@@ -131,10 +149,9 @@ const string &IdentityAddress::getDomain () const {
return d->domain; return d->domain;
} }
bool IdentityAddress::setDomain (const string &domain) { void IdentityAddress::setDomain (const string &domain) {
L_D(); L_D();
d->domain = domain; d->domain = domain;
return true;
} }
bool IdentityAddress::hasGruu () const { bool IdentityAddress::hasGruu () const {
...@@ -147,10 +164,9 @@ const string &IdentityAddress::getGruu () const { ...@@ -147,10 +164,9 @@ const string &IdentityAddress::getGruu () const {
return d->gruu; return d->gruu;
} }
bool IdentityAddress::setGruu (const string &gruu) { void IdentityAddress::setGruu (const string &gruu) {
L_D(); L_D();
d->gruu = gruu; d->gruu = gruu;
return true;
} }
IdentityAddress IdentityAddress::getAddressWithoutGruu () const { IdentityAddress IdentityAddress::getAddressWithoutGruu () const {
......
...@@ -33,9 +33,10 @@ class IdentityAddressPrivate; ...@@ -33,9 +33,10 @@ class IdentityAddressPrivate;
class LINPHONE_PUBLIC IdentityAddress : public ClonableObject { class LINPHONE_PUBLIC IdentityAddress : public ClonableObject {
public: public:
explicit IdentityAddress (const std::string &address = ""); explicit IdentityAddress (const std::string &address);
IdentityAddress (const Address &address); IdentityAddress (const Address &address);
IdentityAddress (const IdentityAddress &other); IdentityAddress (const IdentityAddress &other);
IdentityAddress ();
~IdentityAddress () = default; ~IdentityAddress () = default;
IdentityAddress *clone () const override { IdentityAddress *clone () const override {
...@@ -52,16 +53,17 @@ public: ...@@ -52,16 +53,17 @@ public:
bool isValid () const; bool isValid () const;
const std::string &getScheme () const; const std::string &getScheme () const;
void setScheme (const std::string &scheme);
const std::string &getUsername () const; const std::string &getUsername () const;
bool setUsername (const std::string &username); void setUsername (const std::string &username);
const std::string &getDomain () const; const std::string &getDomain () const;
bool setDomain (const std::string &domain); void setDomain (const std::string &domain);
bool hasGruu () const; bool hasGruu () const;
const std::string &getGruu () const; const std::string &getGruu () const;
bool setGruu (const std::string &gruu); void setGruu (const std::string &gruu);
IdentityAddress getAddressWithoutGruu () const; IdentityAddress getAddressWithoutGruu () const;
......
...@@ -208,6 +208,10 @@ int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) { ...@@ -208,6 +208,10 @@ int linphone_chat_room_get_history_size (LinphoneChatRoom *cr) {
return L_GET_CPP_PTR_FROM_C_OBJECT(cr)->getChatMessageCount(); 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) { void linphone_chat_room_delete_message (LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
shared_ptr<LinphonePrivate::EventLog> event = LinphonePrivate::MainDb::getEventFromKey( shared_ptr<LinphonePrivate::EventLog> event = LinphonePrivate::MainDb::getEventFromKey(
L_GET_PRIVATE_FROM_C_OBJECT(msg)->dbKey L_GET_PRIVATE_FROM_C_OBJECT(msg)->dbKey
......
...@@ -42,6 +42,8 @@ L_DECLARE_C_CLONABLE_OBJECT_IMPL_WITH_XTORS(Content, ...@@ -42,6 +42,8 @@ L_DECLARE_C_CLONABLE_OBJECT_IMPL_WITH_XTORS(Content,
void *cryptoContext; // Used to encrypt file for RCS file transfer. void *cryptoContext; // Used to encrypt file for RCS file transfer.
mutable size_t size; mutable size_t size;
bool_t is_dirty = FALSE;
SalBodyHandler *body_handler;
struct Cache { struct Cache {
string name; string name;
...@@ -49,6 +51,7 @@ L_DECLARE_C_CLONABLE_OBJECT_IMPL_WITH_XTORS(Content, ...@@ -49,6 +51,7 @@ L_DECLARE_C_CLONABLE_OBJECT_IMPL_WITH_XTORS(Content,
string subtype; string subtype;
string buffer; string buffer;
string file_path; string file_path;
string header_value;
} mutable cache; } mutable cache;
) )
...@@ -58,12 +61,14 @@ static void _linphone_content_constructor (LinphoneContent *content) { ...@@ -58,12 +61,14 @@ static void _linphone_content_constructor (LinphoneContent *content) {
static void _linphone_content_destructor (LinphoneContent *content) { static void _linphone_content_destructor (LinphoneContent *content) {
content->cache.~Cache(); 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) { static void _linphone_content_c_clone (LinphoneContent *dest, const LinphoneContent *src) {
new(&dest->cache) LinphoneContent::Cache(); new(&dest->cache) LinphoneContent::Cache();
dest->size = src->size; dest->size = src->size;
dest->cache = src->cache; 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) { ...@@ -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) { 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); 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) ...@@ -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) { 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)); 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) { ...@@ -188,12 +195,47 @@ bool_t linphone_content_is_multipart (const LinphoneContent *content) {
return L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType().isMultipart(); 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) { 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)) { if (!sal_body_handler_is_multipart(bodyHandler)) {
sal_body_handler_unref(bodyHandler); sal_body_handler_unref(bodyHandler);
return nullptr; return nullptr;
} }
SalBodyHandler *partBodyHandler = sal_body_handler_get_part(bodyHandler, idx); SalBodyHandler *partBodyHandler = sal_body_handler_get_part(bodyHandler, idx);
LinphoneContent *result = linphone_content_from_sal_body_handler(partBodyHandler); LinphoneContent *result = linphone_content_from_sal_body_handler(partBodyHandler);
sal_body_handler_unref(bodyHandler); sal_body_handler_unref(bodyHandler);
...@@ -201,11 +243,18 @@ LinphoneContent *linphone_content_get_part (const LinphoneContent *content, int ...@@ -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) { 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)) { if (!sal_body_handler_is_multipart(bodyHandler)) {
sal_body_handler_unref(bodyHandler); sal_body_handler_unref(bodyHandler);
return nullptr; return nullptr;
} }
SalBodyHandler *partBodyHandler = sal_body_handler_find_part_by_header(bodyHandler, headerName, headerValue); SalBodyHandler *partBodyHandler = sal_body_handler_find_part_by_header(bodyHandler, headerName, headerValue);
LinphoneContent *result = linphone_content_from_sal_body_handler(partBodyHandler); LinphoneContent *result = linphone_content_from_sal_body_handler(partBodyHandler);
sal_body_handler_unref(bodyHandler); sal_body_handler_unref(bodyHandler);
...@@ -213,10 +262,16 @@ LinphoneContent *linphone_content_find_part_by_header (const LinphoneContent *co ...@@ -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) { const char *linphone_content_get_custom_header (const LinphoneContent *content, const char *headerName) {
SalBodyHandler *bodyHandler = sal_body_handler_from_content(content); SalBodyHandler *bodyHandler;
const char *header = sal_body_handler_get_header(bodyHandler, headerName); 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); sal_body_handler_unref(bodyHandler);
return header; return content->cache.header_value.c_str();
} }
const char *linphone_content_get_key (const LinphoneContent *content) { const char *linphone_content_get_key (const LinphoneContent *content) {
...@@ -287,10 +342,13 @@ static LinphoneContent *linphone_content_new_with_body_handler (const SalBodyHan ...@@ -287,10 +342,13 @@ static LinphoneContent *linphone_content_new_with_body_handler (const SalBodyHan
content->cryptoContext = nullptr; content->cryptoContext = nullptr;
LinphonePrivate::Content *c = new LinphonePrivate::Content(); LinphonePrivate::Content *c = new LinphonePrivate::Content();
L_SET_CPP_PTR_FROM_C_OBJECT(content, c); L_SET_CPP_PTR_FROM_C_OBJECT(content, c);
content->body_handler = nullptr;
if (!bodyHandler) if (!bodyHandler)
return content; 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_type(content, sal_body_handler_get_type(bodyHandler));
linphone_content_set_subtype(content, sal_body_handler_get_subtype(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) { 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 ...@@ -349,6 +407,9 @@ SalBodyHandler *sal_body_handler_from_content (const LinphoneContent *content, b
if (!content) if (!content)
return nullptr; return nullptr;
if (!content->is_dirty && content->body_handler)
return sal_body_handler_ref(content->body_handler);
SalBodyHandler *bodyHandler; SalBodyHandler *bodyHandler;
LinphonePrivate::ContentType contentType = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType(); LinphonePrivate::ContentType contentType = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
if (contentType.isMultipart() && parseMultipart) { if (contentType.isMultipart() && parseMultipart) {
......
...@@ -127,3 +127,7 @@ void linphone_core_enable_friend_list_subscription(LinphoneCore *lc, bool_t enab ...@@ -127,3 +127,7 @@ void linphone_core_enable_friend_list_subscription(LinphoneCore *lc, bool_t enab
bool_t linphone_core_is_friend_list_subscription_enabled(LinphoneCore *lc) { bool_t linphone_core_is_friend_list_subscription_enabled(LinphoneCore *lc) {
return L_GET_CPP_PTR_FROM_C_OBJECT(lc)->isFriendListSubscriptionEnabled() ? TRUE : FALSE; return L_GET_CPP_PTR_FROM_C_OBJECT(lc)->isFriendListSubscriptionEnabled() ? TRUE : FALSE;
} }
void linphone_core_ensure_registered(LinphoneCore *lc) {
L_GET_CPP_PTR_FROM_C_OBJECT(lc)->pushNotificationReceived();
}
\ No newline at end of file
...@@ -356,7 +356,7 @@ void ChatMessagePrivate::setExternalBodyUrl (const string &url) { ...@@ -356,7 +356,7 @@ void ChatMessagePrivate::setExternalBodyUrl (const string &url) {
const ContentType &ChatMessagePrivate::getContentType () const { const ContentType &ChatMessagePrivate::getContentType () const {
loadContentsFromDatabase(); loadContentsFromDatabase();
if (direction == ChatMessage::Direction::Incoming) { if (direction == ChatMessage::Direction::Incoming) {
if (contents.size() > 0) { if (!contents.empty()) {
Content *content = contents.front(); Content *content = contents.front();
cContentType = content->getContentType(); cContentType = content->getContentType();
} else { } else {
...@@ -366,7 +366,7 @@ const ContentType &ChatMessagePrivate::getContentType () const { ...@@ -366,7 +366,7 @@ const ContentType &ChatMessagePrivate::getContentType () const {
if (internalContent.getContentType().isValid()) { if (internalContent.getContentType().isValid()) {
cContentType = internalContent.getContentType(); cContentType = internalContent.getContentType();
} else { } else {
if (contents.size() > 0) { if (!contents.empty()) {
Content *content = contents.front(); Content *content = contents.front();
cContentType = content->getContentType(); cContentType = content->getContentType();
} }
...@@ -377,14 +377,14 @@ const ContentType &ChatMessagePrivate::getContentType () const { ...@@ -377,14 +377,14 @@ const ContentType &ChatMessagePrivate::getContentType () const {
void ChatMessagePrivate::setContentType (const ContentType &contentType) { void ChatMessagePrivate::setContentType (const ContentType &contentType) {
loadContentsFromDatabase(); loadContentsFromDatabase();
if (contents.size() > 0 && internalContent.getContentType().isEmpty() && internalContent.isEmpty()) { if (!contents.empty() && internalContent.getContentType().isEmpty() && internalContent.isEmpty()) {
internalContent.setBody(contents.front()->getBody()); internalContent.setBody(contents.front()->getBody());
} }
internalContent.setContentType(contentType); internalContent.setContentType(contentType);
if ((currentSendStep &ChatMessagePrivate::Step::Started) != ChatMessagePrivate::Step::Started) { if ((currentSendStep &ChatMessagePrivate::Step::Started) != ChatMessagePrivate::Step::Started) {
// if not started yet the sending also alter the first content // if not started yet the sending also alter the first content
if (contents.size() > 0) if (!contents.empty())
contents.front()->setContentType(contentType); contents.front()->setContentType(contentType);
} }
} }
...@@ -394,7 +394,7 @@ const string &ChatMessagePrivate::getText () const { ...@@ -394,7 +394,7 @@ const string &ChatMessagePrivate::getText () const {
if (direction == ChatMessage::Direction::Incoming) { if (direction == ChatMessage::Direction::Incoming) {
if (hasTextContent()) { if (hasTextContent()) {
cText = getTextContent()->getBodyAsString(); cText = getTextContent()->getBodyAsString();
} else if (contents.size() > 0) { } else if (!contents.empty()) {
Content *content = contents.front(); Content *content = contents.front();
cText = content->getBodyAsString(); cText = content->getBodyAsString();
} else { } else {
...@@ -404,7 +404,7 @@ const string &ChatMessagePrivate::getText () const { ...@@ -404,7 +404,7 @@ const string &ChatMessagePrivate::getText () const {
if (!internalContent.isEmpty()) { if (!internalContent.isEmpty()) {
cText = internalContent.getBodyAsString(); cText = internalContent.getBodyAsString();
} else { } else {
if (contents.size() > 0) { if (!contents.empty()) {
Content *content = contents.front(); Content *content = contents.front();
cText = content->getBodyAsString(); cText = content->getBodyAsString();
} }
...@@ -415,14 +415,14 @@ const string &ChatMessagePrivate::getText () const { ...@@ -415,14 +415,14 @@ const string &ChatMessagePrivate::getText () const {
void ChatMessagePrivate::setText (const string &text) { void ChatMessagePrivate::setText (const string &text) {
loadContentsFromDatabase(); loadContentsFromDatabase();
if (contents.size() > 0 && internalContent.getContentType().isEmpty() && internalContent.isEmpty()) { if (!contents.empty() && internalContent.getContentType().isEmpty() && internalContent.isEmpty()) {
internalContent.setContentType(contents.front()->getContentType()); internalContent.setContentType(contents.front()->getContentType());
} }
internalContent.setBody(text); internalContent.setBody(text);
if ((currentSendStep &ChatMessagePrivate::Step::Started) != ChatMessagePrivate::Step::Started) { if ((currentSendStep &ChatMessagePrivate::Step::Started) != ChatMessagePrivate::Step::Started) {
// if not started yet the sending also alter the first content // if not started yet the sending also alter the first content
if (contents.size() > 0) if (!contents.empty())
contents.front()->setBody(text); contents.front()->setBody(text);
} }
} }
...@@ -648,7 +648,7 @@ LinphoneReason ChatMessagePrivate::receive () { ...@@ -648,7 +648,7 @@ LinphoneReason ChatMessagePrivate::receive () {
q->getChatRoom()->getPrivate()->removeTransientChatMessage(q->getSharedFromThis()); 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 // All previous modifiers only altered the internal content, let's fill the content list
contents.push_back(new Content(internalContent)); contents.push_back(new Content(internalContent));
} }
...@@ -868,7 +868,7 @@ void ChatMessagePrivate::send () { ...@@ -868,7 +868,7 @@ void ChatMessagePrivate::send () {
// --------------------------------------- // ---------------------------------------
if (internalContent.isEmpty()) { if (internalContent.isEmpty()) {
if (contents.size() > 0) { if (!contents.empty()) {
internalContent = *(contents.front()); internalContent = *(contents.front());
} else if (externalBodyUrl.empty()) { // When using external body url, there is no content } else if (externalBodyUrl.empty()) { // When using external body url, there is no content
lError() << "Trying to send a message without any content !"; lError() << "Trying to send a message without any content !";
......
...@@ -47,7 +47,7 @@ public: ...@@ -47,7 +47,7 @@ public:
virtual void addTransientEvent (const std::shared_ptr<EventLog> &eventLog) = 0; virtual void addTransientEvent (const std::shared_ptr<EventLog> &eventLog) = 0;
virtual void removeTransientEvent (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 notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
virtual void notifyUndecryptableChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) = 0; virtual void notifyUndecryptableChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
......
...@@ -81,7 +81,7 @@ public: ...@@ -81,7 +81,7 @@ public:
virtual void deleteHistory () = 0; virtual void deleteHistory () = 0;
virtual std::shared_ptr<ChatMessage> getLastChatMessageInHistory () const = 0; virtual std::shared_ptr<ChatMessage> getLastChatMessageInHistory () const = 0;
virtual bool isEmpty () const = 0;
virtual int getChatMessageCount () const = 0; virtual int getChatMessageCount () const = 0;
virtual int getUnreadChatMessageCount () const = 0; virtual int getUnreadChatMessageCount () const = 0;
......
...@@ -75,7 +75,7 @@ public: ...@@ -75,7 +75,7 @@ public:
void sendDeliveryErrorNotification (const std::shared_ptr<ChatMessage> &chatMessage, LinphoneReason reason); void sendDeliveryErrorNotification (const std::shared_ptr<ChatMessage> &chatMessage, LinphoneReason reason);
void sendDeliveryNotification (const std::shared_ptr<ChatMessage> &chatMessage); 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 sendDisplayNotification (const std::shared_ptr<ChatMessage> &chatMessage);
void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override; void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override;
......