Merge branch 'dev_refactor_cpp' into dev_chatroom_list_subscription

This commit is contained in:
Benjamin Reis 2018-05-09 16:19:26 +02:00
commit e4422ca7e6
189 changed files with 16192 additions and 5355 deletions

View file

@ -182,6 +182,19 @@ if(UNIX AND NOT APPLE)
check_include_files(libudev.h HAVE_LIBUDEV_H)
endif()
if(MSVC AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
find_library(LIBGCC NAMES gcc)
find_library(LIBMINGWEX NAMES mingwex)
endif()
if(NOT WIN32)
find_package(Iconv QUIET)
endif()
if(ANDROID)
find_package(CpuFeatures REQUIRED)
find_package(Support REQUIRED)
endif()
set(LINPHONE_LDFLAGS "${BELLESIP_LDFLAGS} ${MEDIASTREAMER2_LDFLAGS}")
if(BELCARD_FOUND AND APPLE)
set(LINPHONE_LDFLAGS "${LINPHONE_LDFLAGS} -stdlib=libc++")
@ -278,7 +291,7 @@ else()
)
CHECK_CXX_COMPILER_FLAG("-Wsuggest-override" SUGGEST_OVERRIDE)
if (SUGGEST_OVERRIDE)
list(APPEND STRICT_OPTIONS_CXX "-Wsuggest-override" "-Werror=suggest-override")
list(APPEND STRICT_OPTIONS_CXX "-Wsuggest-override" "-Wno-error=suggest-override" )
endif ()
list(APPEND STRICT_OPTIONS_C "-Wstrict-prototypes" "-Werror=strict-prototypes")
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
@ -342,8 +355,8 @@ add_subdirectory(java)
if(ENABLE_JAVA_WRAPPER)
add_subdirectory(wrappers/java)
endif()
add_subdirectory(src)
add_subdirectory(coreapi)
add_subdirectory(src)
add_subdirectory(share)
if(ENABLE_CONSOLE_UI)
add_subdirectory(console)

View file

@ -20,19 +20,6 @@
#
############################################################################
if(MSVC AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
find_library(LIBGCC NAMES gcc)
find_library(LIBMINGWEX NAMES mingwex)
endif()
if(NOT WIN32)
find_package(Iconv QUIET)
endif()
if(ANDROID)
find_package(CpuFeatures REQUIRED)
find_package(Support REQUIRED)
endif()
list(APPEND LINPHONE_PRIVATE_HEADER_FILES
bellesip_sal/sal_impl.h
carddav.h
@ -136,55 +123,7 @@ else()
list(APPEND LINPHONE_SOURCE_FILES_C linphone_tunnel_stubs.c)
endif()
bc_git_version(liblinphone ${PROJECT_VERSION})
add_definitions(
-DUSE_BELLESIP
-DLIBLINPHONE_EXPORTS
-DBCTBX_LOG_DOMAIN="liblinphone"
)
set(LIBS
${BCTOOLBOX_CORE_LIBRARIES}
${BELLESIP_LIBRARIES}
${MEDIASTREAMER2_LIBRARIES}
${ORTP_LIBRARIES}
${XML2_LIBRARIES}
${BELR_LIBRARIES}
${LIBXSD_LIBRARIES}
)
if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
list(APPEND LIBS "Ws2_32")
endif()
if(ENABLE_LIME)
list(APPEND LIBS ${BZRTP_LIBRARIES})
endif()
if(ZLIB_FOUND)
list(APPEND LIBS ${ZLIB_LIBRARIES})
endif()
if(SOCI_FOUND)
list(APPEND LIBS ${SOCI_LIBRARIES})
endif()
if(SQLITE3_FOUND)
list(APPEND LIBS ${SQLITE3_LIBRARIES})
endif()
if(ICONV_FOUND)
list(APPEND LIBS ${ICONV_LIBRARIES})
endif()
if(ENABLE_TUNNEL)
list(APPEND LIBS ${TUNNEL_LIBRARIES})
endif()
if(MSVC AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
list(APPEND LIBS ${LIBGCC} ${LIBMINGWEX})
endif()
if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
list(APPEND LIBS shlwapi)
endif()
if(INTL_FOUND)
list(APPEND LIBS ${INTL_LIBRARIES})
endif()
if(BELCARD_FOUND)
list(APPEND LIBS ${BELCARD_LIBRARIES})
list(APPEND LINPHONE_SOURCE_FILES_CXX vcard.cc)
if(NOT MSVC)
list(APPEND STRICT_OPTIONS_CXX "-std=c++11")
@ -196,106 +135,37 @@ else()
list(APPEND LINPHONE_SOURCE_FILES_C vcard_stubs.c)
endif()
bc_git_version(liblinphone ${PROJECT_VERSION})
add_definitions(
-DUSE_BELLESIP
-DLIBLINPHONE_EXPORTS
-DBCTBX_LOG_DOMAIN="liblinphone"
)
set_source_files_properties(${LINPHONE_SOURCE_FILES_C} PROPERTIES LANGUAGE CXX)
bc_apply_compile_flags(LINPHONE_SOURCE_FILES_C STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX)
bc_apply_compile_flags(LINPHONE_SOURCE_FILES_CXX STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX)
bc_apply_compile_flags(LINPHONE_SOURCE_FILES_OBJC STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC)
if(ENABLE_STATIC)
add_library(linphone-static STATIC ${LINPHONE_HEADER_FILES} ${LINPHONE_PRIVATE_HEADER_FILES}
${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC}
$<TARGET_OBJECTS:linphone-cxx-objects-static>
)
set_target_properties(linphone-static PROPERTIES OUTPUT_NAME linphone)
add_dependencies(linphone-static liblinphone-git-version)
target_include_directories(linphone-static PUBLIC ${LINPHONE_INCLUDE_DIRS})
target_link_libraries(linphone-static INTERFACE ${LIBS})
if(APPLE)
target_link_libraries(linphone-static INTERFACE "-framework Foundation" "-framework AVFoundation")
endif()
install(TARGETS linphone-static EXPORT ${EXPORT_TARGETS_NAME}Targets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
endif()
if(ENABLE_SHARED)
add_library(linphone SHARED "../share/cpim_grammar" ${LINPHONE_HEADER_FILES} ${LINPHONE_PRIVATE_HEADER_FILES}
${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC}
$<TARGET_OBJECTS:linphone-cxx-objects>
)
if(IOS)
if(IOS)
set(MIN_OS ${LINPHONE_IOS_DEPLOYMENT_TARGET})
else()
set(MIN_OS ${CMAKE_OSX_DEPLOYMENT_TARGET})
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/build/osx/")
set_target_properties(linphone PROPERTIES
FRAMEWORK TRUE
MACOSX_FRAMEWORK_IDENTIFIER org.linphone.linphone
MACOSX_FRAMEWORK_INFO_PLIST Info.plist.in
PUBLIC_HEADER "${LINPHONE_HEADER_FILES}"
RESOURCE "../share/cpim_grammar"
)
endif()
if(BELCARD_FOUND)
if(APPLE)
set_target_properties(linphone PROPERTIES LINK_FLAGS "-stdlib=libc++")
endif()
endif()
set_target_properties(linphone PROPERTIES LINKER_LANGUAGE CXX)
if(NOT ANDROID)
# Do not version shared library on Android
set_target_properties(linphone PROPERTIES SOVERSION ${LINPHONE_SO_VERSION})
endif()
add_dependencies(linphone liblinphone-git-version)
target_include_directories(linphone PUBLIC ${LINPHONE_INCLUDE_DIRS})
target_link_libraries(linphone PRIVATE ${LIBS})
if(APPLE)
target_link_libraries(linphone PRIVATE "-framework Foundation" "-framework AVFoundation")
endif()
if(WIN32 AND CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
set_target_properties(linphone PROPERTIES PREFIX "lib")
elseif(ANDROID)
target_link_libraries(linphone PUBLIC "log" ${SUPPORT_LIBRARIES} ${CPUFEATURES_LIBRARIES})
if(ENABLE_JAVA_WRAPPER)
add_dependencies(linphone linphonej)
endif()
endif()
if(MSVC)
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/linphone.pdb
DESTINATION ${CMAKE_INSTALL_BINDIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
endif()
endif()
install(TARGETS linphone EXPORT ${EXPORT_TARGETS_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
FRAMEWORK DESTINATION Frameworks
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
if (ENABLE_STATIC)
add_library(linphone-coreapi-static OBJECT
${LINPHONE_PRIVATE_HEADER_FILES} ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC}
)
endif()
if(ICONV_FOUND)
if(APPLE)
# Prevent conflict between the system iconv.h header and the one from macports.
if(ENABLE_STATIC)
target_compile_options(linphone-static PRIVATE "-include" "${ICONV_INCLUDE_DIRS}/iconv.h")
endif()
if(ENABLE_SHARED)
target_compile_options(linphone PRIVATE "-include" "${ICONV_INCLUDE_DIRS}/iconv.h")
endif()
else()
if(ENABLE_STATIC)
target_include_directories(linphone-static PRIVATE ${ICONV_INCLUDE_DIRS})
endif()
if(ENABLE_SHARED)
target_include_directories(linphone PRIVATE ${ICONV_INCLUDE_DIRS})
endif()
endif()
endif()
target_include_directories(linphone-coreapi-static SYSTEM PRIVATE ${LINPHONE_INCLUDE_DIRS})
add_dependencies(linphone-coreapi-static liblinphone-git-version)
endif ()
if (ENABLE_SHARED)
add_library(linphone-coreapi OBJECT
${LINPHONE_PRIVATE_HEADER_FILES} ${LINPHONE_SOURCE_FILES_C} ${LINPHONE_SOURCE_FILES_CXX} ${LINPHONE_SOURCE_FILES_OBJC}
)
target_include_directories(linphone-coreapi SYSTEM PRIVATE ${LINPHONE_INCLUDE_DIRS})
target_compile_options(linphone-coreapi PRIVATE "-fPIC")
add_dependencies(linphone-coreapi liblinphone-git-version)
endif ()
add_subdirectory(help)

View file

@ -33,7 +33,7 @@ void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPor
return;
}
addServer(ip,port);
mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip,udpMirrorPort),delay));
mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip, (int)udpMirrorPort), delay));
}
void TunnelManager::addServer(const char *ip, int port) {
@ -58,7 +58,7 @@ void TunnelManager::addServerPair(const char *ip1, int port1, const char *ip2, i
return;
}
addServerPair(ip1, port1, ip2, port2);
mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip1, udpMirrorPort), delay));
mUdpMirrorClients.push_back(UdpMirrorClient(ServerAddr(ip1, (int)udpMirrorPort), delay));
}
void TunnelManager::addServerPair(const char *ip1, int port1, const char *ip2, int port2) {
@ -159,7 +159,7 @@ void TunnelManager::startClient() {
mTunnelClient = TunnelClient::create(TRUE);
}
sal_set_tunnel(mCore->sal, mTunnelClient);
mCore->sal->setTunnel(mTunnelClient);
if (!mUseDualClient) {
static_cast<TunnelClient*>(mTunnelClient)->setCallback(tunnelCallback,this);
} else {
@ -220,21 +220,21 @@ bool TunnelManager::isConnected() const {
int TunnelManager::customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen){
int size;
DualSocket *ds = (DualSocket *)t->data;
msgpullup(msg,-1);
size=msgdsize(msg);
ds->sendSocket->sendto(msg->b_rptr,size,to,tolen);
msgpullup(msg, (size_t)-1);
size = (int)msgdsize(msg);
ds->sendSocket->sendto(msg->b_rptr, (size_t)size, to, tolen);
return size;
}
int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen){
DualSocket *ds = (DualSocket *)t->data;
memset(&msg->recv_addr,0,sizeof(msg->recv_addr));
int err=ds->recvSocket->recvfrom(msg->b_wptr,dblk_lim(msg->b_datap)-dblk_base(msg->b_datap),from,*fromlen);
long err=ds->recvSocket->recvfrom(msg->b_wptr, (size_t)(dblk_lim(msg->b_datap) - dblk_base(msg->b_datap)), from, *fromlen);
//to make ice happy
inet_aton(((TunnelManager*)(ds->recvSocket)->getUserPointer())->mLocalAddr,&msg->recv_addr.addr.ipi_addr);
msg->recv_addr.family = AF_INET;
msg->recv_addr.port = htons((unsigned short)(ds->recvSocket)->getPort());
if (err>0) return err;
if (err>0) return (int)err;
return 0;
}
@ -281,7 +281,7 @@ TunnelManager::~TunnelManager(){
mTunnelClient->stop();
delete mTunnelClient;
}
sal_set_tunnel(mCore->sal,NULL);
mCore->sal->setTunnel(NULL);
linphone_core_remove_listener(mCore, mVTable);
linphone_core_v_table_destroy(mVTable);
}

View file

@ -21,11 +21,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "linphone/core.h"
#include "linphone/lpconfig.h"
#include "c-wrapper/c-wrapper.h"
#include "dial-plan/dial-plan.h"
#include <bctoolbox/crypto.h>
#include <bctoolbox/regex.h>
#include "bctoolbox/crypto.h"
#include "bctoolbox/regex.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
@ -266,8 +268,12 @@ void linphone_account_creator_cbs_set_update_account(LinphoneAccountCreatorCbs *
static void _linphone_account_creator_destroy(LinphoneAccountCreator *creator) {
/*this will drop all pending requests if any*/
if (creator->xmlrpc_session) linphone_xml_rpc_session_release(creator->xmlrpc_session);
if (creator->service != NULL && linphone_account_creator_service_get_destructor_cb(creator->service) != NULL)
linphone_account_creator_service_get_destructor_cb(creator->service)(creator);
if (creator->service != NULL ) {
if (linphone_account_creator_service_get_destructor_cb(creator->service) != NULL)
linphone_account_creator_service_get_destructor_cb(creator->service)(creator);
linphone_account_creator_service_unref(creator->service);
}
linphone_account_creator_cbs_unref(creator->cbs);
linphone_proxy_config_unref(creator->proxy_cfg);
linphone_account_creator_reset(creator);
@ -287,6 +293,7 @@ LinphoneAccountCreator * _linphone_account_creator_new(LinphoneCore *core, const
const char* domain = lp_config_get_string(core->config, "assistant", "domain", NULL);
creator = belle_sip_object_new(LinphoneAccountCreator);
creator->service = linphone_core_get_account_creator_service(core);
linphone_account_creator_service_ref(creator->service);
creator->cbs = linphone_account_creator_cbs_new();
creator->core = core;
creator->transport = LinphoneTransportTcp;

View file

@ -472,10 +472,10 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
lc->auth_info=bctbx_list_append(lc->auth_info,linphone_auth_info_clone(info));
/* retry pending authentication operations */
for(l=elem=lc->sal->get_pending_auths();elem!=NULL;elem=elem->next){
for(l=elem=lc->sal->getPendingAuths();elem!=NULL;elem=elem->next){
LinphonePrivate::SalOp *op= static_cast<LinphonePrivate::SalOp*>(elem->data);
LinphoneAuthInfo *ai;
const SalAuthInfo *req_sai=op->get_auth_requested();
const SalAuthInfo *req_sai=op->getAuthRequested();
ai=(LinphoneAuthInfo*)_linphone_core_find_auth_info(lc,req_sai->realm,req_sai->username,req_sai->domain, FALSE);
if (ai){
SalAuthInfo sai;
@ -495,7 +495,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
}
/*proxy case*/
for (proxy=(bctbx_list_t*)linphone_core_get_proxy_config_list(lc);proxy!=NULL;proxy=proxy->next) {
if (proxy->data == op->get_user_pointer()) {
if (proxy->data == op->getUserPointer()) {
linphone_proxy_config_set_state((LinphoneProxyConfig*)(proxy->data),LinphoneRegistrationProgress,"Authentication...");
break;
}

View file

@ -58,10 +58,11 @@ using namespace LinphonePrivate;
static void register_failure(SalOp *op);
static void call_received(SalCallOp *h) {
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(h->get_sal()->get_user_pointer());
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(h->getSal()->getUserPointer());
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
h->decline(SalReasonServiceUnavailable, nullptr);
h->release();
return;
}
@ -70,13 +71,13 @@ static void call_received(SalCallOp *h) {
return;
LinphoneAddress *fromAddr = nullptr;
const char *pAssertedId = sal_custom_header_find(h->get_recv_custom_header(), "P-Asserted-Identity");
const char *pAssertedId = sal_custom_header_find(h->getRecvCustomHeaders(), "P-Asserted-Identity");
/* In some situation, better to trust the network rather than the UAC */
if (lp_config_get_int(linphone_core_get_config(lc), "sip", "call_logs_use_asserted_id_instead_of_from", 0)) {
if (pAssertedId) {
LinphoneAddress *pAssertedIdAddr = linphone_address_new(pAssertedId);
if (pAssertedIdAddr) {
ms_message("Using P-Asserted-Identity [%s] instead of from [%s] for op [%p]", pAssertedId, h->get_from(), h);
ms_message("Using P-Asserted-Identity [%s] instead of from [%s] for op [%p]", pAssertedId, h->getFrom(), h);
fromAddr = pAssertedIdAddr;
} else
ms_warning("Unsupported P-Asserted-Identity header for op [%p] ", h);
@ -85,22 +86,23 @@ static void call_received(SalCallOp *h) {
}
if (!fromAddr)
fromAddr = linphone_address_new(h->get_from());
LinphoneAddress *toAddr = linphone_address_new(h->get_to());
fromAddr = linphone_address_new(h->getFrom());
LinphoneAddress *toAddr = linphone_address_new(h->getTo());
if (_linphone_core_is_conference_creation(lc, toAddr)) {
linphone_address_unref(toAddr);
linphone_address_unref(fromAddr);
if (sal_address_has_param(h->get_remote_contact_address(), "text")) {
if (sal_address_has_param(h->getRemoteContactAddress(), "text")) {
bool oneToOneChatRoom = false;
const char *oneToOneChatRoomStr = sal_custom_header_find(h->get_recv_custom_header(), "One-To-One-Chat-Room");
const char *oneToOneChatRoomStr = sal_custom_header_find(h->getRecvCustomHeaders(), "One-To-One-Chat-Room");
if (oneToOneChatRoomStr && (strcmp(oneToOneChatRoomStr, "true") == 0))
oneToOneChatRoom = true;
if (oneToOneChatRoom) {
IdentityAddress from(h->get_from());
list<IdentityAddress> identAddresses = ServerGroupChatRoom::parseResourceLists(h->get_remote_body());
IdentityAddress from(h->getFrom());
list<IdentityAddress> identAddresses = ServerGroupChatRoom::parseResourceLists(h->getRemoteBody());
if (identAddresses.size() != 1) {
h->decline(SalReasonNotAcceptable, nullptr);
h->release();
return;
}
IdentityAddress confAddr = L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb->findOneToOneConferenceChatRoomAddress(from, identAddresses.front());
@ -114,26 +116,27 @@ static void call_received(SalCallOp *h) {
}
// TODO: handle media conference creation if the "text" feature tag is not present
return;
} else if (sal_address_has_param(h->get_remote_contact_address(), "text")) {
} else if (sal_address_has_param(h->getRemoteContactAddress(), "text")) {
linphone_address_unref(toAddr);
linphone_address_unref(fromAddr);
if (linphone_core_conference_server_enabled(lc)) {
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
ChatRoomId(IdentityAddress(h->get_to()), IdentityAddress(h->get_to()))
ChatRoomId(IdentityAddress(h->getTo()), IdentityAddress(h->getTo()))
);
if (chatRoom) {
L_GET_PRIVATE(static_pointer_cast<ServerGroupChatRoom>(chatRoom))->confirmJoining(h);
} else {
//invite is for an unknown chatroom
h->decline(SalReasonNotFound, nullptr);
h->release();
}
} else {
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
ChatRoomId(IdentityAddress(h->get_from()), IdentityAddress(h->get_to()))
ChatRoomId(IdentityAddress(h->getFrom()), IdentityAddress(h->getTo()))
);
if (!chatRoom) {
chatRoom = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createClientGroupChatRoom(
L_C_TO_STRING(h->get_subject()), h->get_remote_contact(), h->get_remote_body(), false
L_C_TO_STRING(h->getSubject()), h->getRemoteContact(), h->getRemoteBody(), false
);
}
L_GET_PRIVATE(static_pointer_cast<ClientGroupChatRoom>(chatRoom))->confirmJoining(h);
@ -156,7 +159,7 @@ static void call_received(SalCallOp *h) {
memset(&sei, 0, sizeof(sei));
sal_error_info_set(&sei, SalReasonRedirect, "SIP", 0, nullptr, nullptr);
SalAddress *altAddr = sal_address_new(altContact);
h->decline_with_error_info(&sei, altAddr);
h->declineWithErrorInfo(&sei, altAddr);
ms_free(altContact);
sal_address_unref(altAddr);
LinphoneErrorInfo *ei = linphone_error_info_new();
@ -184,7 +187,7 @@ static void call_received(SalCallOp *h) {
/* Check if I'm the caller */
LinphoneAddress *fromAddressToSearchIfMe = nullptr;
if (h->get_privacy() == SalPrivacyNone)
if (h->getPrivacy() == SalPrivacyNone)
fromAddressToSearchIfMe = linphone_address_clone(fromAddr);
else if (pAssertedId)
fromAddressToSearchIfMe = linphone_address_new(pAssertedId);
@ -212,14 +215,14 @@ static void call_received(SalCallOp *h) {
}
static void call_rejected(SalCallOp *h){
LinphoneCore *lc=(LinphoneCore *)h->get_sal()->get_user_pointer();
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(h->getSal()->getUserPointer());
LinphoneErrorInfo *ei = linphone_error_info_new();
linphone_error_info_from_sal_op(ei, h);
linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, linphone_address_new(h->get_from()), linphone_address_new(h->get_to()), ei);
linphone_core_report_early_failed_call(lc, LinphoneCallIncoming, linphone_address_new(h->getFrom()), linphone_address_new(h->getTo()), ei);
}
static void call_ringing(SalOp *h) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(h->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(h->getUserPointer());
if (!session) return;
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->remoteRinging();
@ -231,7 +234,7 @@ static void call_ringing(SalOp *h) {
* - when a request is accepted (pause, resume)
*/
static void call_accepted(SalOp *op) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session) {
ms_warning("call_accepted: CallSession no longer exists");
return;
@ -242,7 +245,7 @@ static void call_accepted(SalOp *op) {
/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
static void call_updating(SalOp *op, bool_t is_update) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session) {
ms_warning("call_updating: CallSession no longer exists");
return;
@ -253,7 +256,7 @@ static void call_updating(SalOp *op, bool_t is_update) {
static void call_ack_received(SalOp *op, SalCustomHeader *ack) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session) {
ms_warning("call_ack_received(): no CallSession for which an ack is expected");
return;
@ -264,7 +267,7 @@ static void call_ack_received(SalOp *op, SalCustomHeader *ack) {
static void call_ack_being_sent(SalOp *op, SalCustomHeader *ack) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session) {
ms_warning("call_ack_being_sent(): no CallSession for which an ack is supposed to be sent");
return;
@ -274,7 +277,7 @@ static void call_ack_being_sent(SalOp *op, SalCustomHeader *ack) {
}
static void call_terminated(SalOp *op, const char *from) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session)
return;
auto sessionRef = session->getSharedFromThis();
@ -282,7 +285,7 @@ static void call_terminated(SalOp *op, const char *from) {
}
static void call_failure(SalOp *op) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session) {
ms_warning("Failure reported on already terminated CallSession");
return;
@ -292,7 +295,7 @@ static void call_failure(SalOp *op) {
}
static void call_released(SalOp *op) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session) {
/* We can get here when the core manages call at Sal level without creating a Call object. Typicially,
* when declining an incoming call with busy because maximum number of calls is reached. */
@ -303,7 +306,7 @@ static void call_released(SalOp *op) {
}
static void call_cancel_done(SalOp *op) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session) {
ms_warning("Cancel done reported on already terminated CallSession");
return;
@ -313,7 +316,7 @@ static void call_cancel_done(SalOp *op) {
}
static void auth_failure(SalOp *op, SalAuthInfo* info) {
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(op->get_sal()->get_user_pointer());
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(op->getSal()->getUserPointer());
LinphoneAuthInfo *ai = NULL;
if (info != NULL) {
@ -332,7 +335,7 @@ static void auth_failure(SalOp *op, SalAuthInfo* info) {
}
static void register_success(SalOp *op, bool_t registered){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)op->get_user_pointer();
LinphoneProxyConfig *cfg=(LinphoneProxyConfig *)op->getUserPointer();
if (!cfg){
ms_message("Registration success for deleted proxy config, ignored");
return;
@ -342,8 +345,8 @@ static void register_success(SalOp *op, bool_t registered){
}
static void register_failure(SalOp *op){
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)op->get_user_pointer();
const SalErrorInfo *ei=op->get_error_info();
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)op->getUserPointer();
const SalErrorInfo *ei=op->getErrorInfo();
const char *details=ei->full_string;
if (cfg==NULL){
@ -368,7 +371,7 @@ static void register_failure(SalOp *op){
}
static void vfu_request(SalOp *op) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session)
return;
auto sessionRef = session->getSharedFromThis();
@ -381,7 +384,7 @@ static void vfu_request(SalOp *op) {
}
static void dtmf_received(SalOp *op, char dtmf) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session)
return;
auto sessionRef = session->getSharedFromThis();
@ -394,7 +397,7 @@ static void dtmf_received(SalOp *op, char dtmf) {
}
static void call_refer_received(SalOp *op, const SalAddress *referTo) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
char *addrStr = sal_address_as_string_uri_only(referTo);
Address referToAddr(addrStr);
string method;
@ -404,21 +407,21 @@ static void call_refer_received(SalOp *op, const SalAddress *referTo) {
auto sessionRef = session->getSharedFromThis();
L_GET_PRIVATE(sessionRef)->referred(referToAddr);
} else {
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(op->get_sal()->get_user_pointer());
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(op->getSal()->getUserPointer());
linphone_core_notify_refer_received(lc, addrStr);
}
bctbx_free(addrStr);
}
static void message_received(SalOp *op, const SalMessage *msg){
LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer();
LinphoneCore *lc=(LinphoneCore *)op->getSal()->getUserPointer();
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
static_cast<SalMessageOp *>(op)->reply(SalReasonServiceUnavailable);
return;
}
LinphoneCall *call=(LinphoneCall*)op->get_user_pointer();
LinphoneCall *call=(LinphoneCall*)op->getUserPointer();
LinphoneReason reason = lc->chat_deny_code;
if (reason == LinphoneReasonNone) {
linphone_core_message_received(lc, op, msg);
@ -444,12 +447,12 @@ static void convert_presence_to_xml_requested(SalOp *op, SalPresenceModel *prese
}
static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg){
LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer();
LinphoneCore *lc=(LinphoneCore *)op->getSal()->getUserPointer();
linphone_notify_recv(lc,op,ss,model);
}
static void subscribe_presence_received(SalPresenceOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer();
LinphoneCore *lc=(LinphoneCore *)op->getSal()->getUserPointer();
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
op->decline(SalReasonServiceUnavailable);
return;
@ -458,12 +461,12 @@ static void subscribe_presence_received(SalPresenceOp *op, const char *from){
}
static void subscribe_presence_closed(SalPresenceOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer();
LinphoneCore *lc=(LinphoneCore *)op->getSal()->getUserPointer();
linphone_subscription_closed(lc,op);
}
static void ping_reply(SalOp *op) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session) {
ms_warning("Ping reply without CallSession attached...");
return;
@ -549,7 +552,7 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) {
}
}
static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) {
LinphoneCore *lc = (LinphoneCore *)sal->get_user_pointer();
LinphoneCore *lc = (LinphoneCore *)sal->getUserPointer();
if (fill_auth_info(lc,sai)) {
return TRUE;
} else {
@ -567,7 +570,7 @@ static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) {
}
static void notify_refer(SalOp *op, SalReferStatus status) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session) {
ms_warning("Receiving notify_refer for unknown CallSession");
return;
@ -604,7 +607,13 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalMessageDeliveryStatus
}
static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status) {
LinphonePrivate::ChatMessage *msg = reinterpret_cast<LinphonePrivate::ChatMessage *>(op->get_user_pointer());
auto lc = reinterpret_cast<LinphoneCore *>(op->getSal()->getUserPointer());
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
static_cast<SalReferOp *>(op)->reply(SalReasonDeclined);
return;
}
LinphonePrivate::ChatMessage *msg = reinterpret_cast<LinphonePrivate::ChatMessage *>(op->getUserPointer());
if (!msg)
return; // Do not handle delivery status for isComposing messages.
@ -614,7 +623,7 @@ static void message_delivery_update(SalOp *op, SalMessageDeliveryStatus status)
}
static void info_received(SalOp *op, SalBodyHandler *body_handler) {
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->get_user_pointer());
LinphonePrivate::CallSession *session = reinterpret_cast<LinphonePrivate::CallSession *>(op->getUserPointer());
if (!session)
return;
auto sessionRef = session->getSharedFromThis();
@ -622,7 +631,7 @@ static void info_received(SalOp *op, SalBodyHandler *body_handler) {
}
static void subscribe_response(SalOp *op, SalSubscribeStatus status, int will_retry){
LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer();
LinphoneEvent *lev=(LinphoneEvent*)op->getUserPointer();
if (lev==NULL) return;
@ -639,8 +648,8 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status, int will_re
}
static void notify(SalSubscribeOp *op, SalSubscribeStatus st, const char *eventname, SalBodyHandler *body_handler){
LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer();
LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer();
LinphoneEvent *lev=(LinphoneEvent*)op->getUserPointer();
LinphoneCore *lc=(LinphoneCore *)op->getSal()->getUserPointer();
bool_t out_of_dialog = (lev==NULL);
if (out_of_dialog) {
/*out of dialog notify */
@ -661,9 +670,9 @@ static void notify(SalSubscribeOp *op, SalSubscribeStatus st, const char *eventn
}
}
static void subscribe_received(SalSubscribeOp *op, const char *eventname, SalBodyHandler *body_handler){
LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer();
LinphoneCore *lc=(LinphoneCore *)op->get_sal()->get_user_pointer();
static void subscribe_received(SalSubscribeOp *op, const char *eventname, const SalBodyHandler *body_handler){
LinphoneEvent *lev=(LinphoneEvent*)op->getUserPointer();
LinphoneCore *lc=(LinphoneCore *)op->getSal()->getUserPointer();
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
op->decline(SalReasonServiceUnavailable);
@ -684,14 +693,14 @@ static void subscribe_received(SalSubscribeOp *op, const char *eventname, SalBod
}
static void incoming_subscribe_closed(SalOp *op){
LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer();
LinphoneEvent *lev=(LinphoneEvent*)op->getUserPointer();
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
}
static void on_publish_response(SalOp* op){
LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer();
const SalErrorInfo *ei=op->get_error_info();
LinphoneEvent *lev=(LinphoneEvent*)op->getUserPointer();
const SalErrorInfo *ei=op->getErrorInfo();
if (lev==NULL) return;
if (ei->reason==SalReasonNone){
@ -710,7 +719,7 @@ static void on_publish_response(SalOp* op){
static void on_expire(SalOp *op){
LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer();
LinphoneEvent *lev=(LinphoneEvent*)op->getUserPointer();
if (lev==NULL) return;
@ -722,14 +731,14 @@ static void on_expire(SalOp *op){
}
static void on_notify_response(SalOp *op){
LinphoneEvent *lev=(LinphoneEvent*)op->get_user_pointer();
LinphoneEvent *lev=(LinphoneEvent*)op->getUserPointer();
if (!lev)
return;
if (lev->is_out_of_dialog_op) {
switch (linphone_event_get_subscription_state(lev)) {
case LinphoneSubscriptionIncomingReceived:
if (op->get_error_info()->reason == SalReasonNone)
if (op->getErrorInfo()->reason == SalReasonNone)
linphone_event_set_state(lev, LinphoneSubscriptionTerminated);
else
linphone_event_set_state(lev, LinphoneSubscriptionError);
@ -751,7 +760,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){
LinphonePrivate::Address addr(refer_uri);
bctbx_free(refer_uri);
if (addr.isValid()) {
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(op->get_sal()->get_user_pointer());
LinphoneCore *lc = reinterpret_cast<LinphoneCore *>(op->getSal()->getUserPointer());
if (linphone_core_get_global_state(lc) != LinphoneGlobalOn) {
static_cast<SalReferOp *>(op)->reply(SalReasonDeclined);
@ -762,10 +771,10 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){
if (linphone_core_conference_server_enabled(lc)) {
// Removal of a participant at the server side
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))
ChatRoomId(IdentityAddress(op->getTo()), IdentityAddress(op->getTo()))
);
if (chatRoom) {
std::shared_ptr<Participant> participant = chatRoom->findParticipant(IdentityAddress(op->get_from()));
std::shared_ptr<Participant> participant = chatRoom->findParticipant(IdentityAddress(op->getFrom()));
if (!participant || !participant->isAdmin()) {
static_cast<SalReferOp *>(op)->reply(SalReasonDeclined);
return;
@ -779,7 +788,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){
} else {
// The server asks a participant to leave a chat room
LinphoneChatRoom *cr = L_GET_C_BACK_PTR(
L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ChatRoomId(addr, IdentityAddress(op->get_to())))
L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(ChatRoomId(addr, IdentityAddress(op->getTo())))
);
if (cr) {
L_GET_CPP_PTR_FROM_C_OBJECT(cr)->leave();
@ -791,11 +800,11 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){
} else {
if (linphone_core_conference_server_enabled(lc)) {
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))
ChatRoomId(IdentityAddress(op->getTo()), IdentityAddress(op->getTo()))
);
LinphoneChatRoom *cr = L_GET_C_BACK_PTR(chatRoom);
if (cr) {
Address fromAddr(op->get_from());
Address fromAddr(op->getFrom());
shared_ptr<Participant> participant = chatRoom->findParticipant(fromAddr);
if (!participant || !participant->isAdmin()) {
static_cast<SalReferOp *>(op)->reply(SalReasonDeclined);
@ -815,7 +824,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){
list<IdentityAddress> identAddresses;
identAddresses.push_back(addr);
L_GET_PRIVATE(static_pointer_cast<ServerGroupChatRoom>(chatRoom))->checkCompatibleParticipants(
IdentityAddress(op->get_remote_contact()),
IdentityAddress(op->getRemoteContact()),
identAddresses
);
static_cast<SalReferOp *>(op)->reply(SalReasonNone);
@ -825,7 +834,7 @@ static void refer_received(SalOp *op, const SalAddress *refer_to){
}
} else {
shared_ptr<AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(
ChatRoomId(addr, IdentityAddress(op->get_to()))
ChatRoomId(addr, IdentityAddress(op->getTo()))
);
if (!chatRoom)
chatRoom = L_GET_PRIVATE_FROM_C_OBJECT(lc)->createClientGroupChatRoom("", addr.asString(), Content(), false);

View file

@ -573,7 +573,7 @@ static char* generate_url_from_server_address_and_uid(const char *server_url) {
char *result = NULL;
if (server_url) {
char *uuid = reinterpret_cast<char *>(ms_malloc(64));
if (LinphonePrivate::Sal::generate_uuid(uuid, 64) == 0) {
if (LinphonePrivate::Sal::generateUuid(uuid, 64) == 0) {
char *url = reinterpret_cast<char *>(ms_malloc(300));
snprintf(url, 300, "%s/linphone-%s.vcf", server_url, uuid);
ms_debug("Generated url is %s", url);

View file

@ -127,10 +127,10 @@ int linphone_core_message_received(LinphoneCore *lc, LinphonePrivate::SalOp *op,
const char *peerAddress;
const char *localAddress;
if (linphone_core_conference_server_enabled(lc)) {
localAddress = peerAddress = op->get_to();
localAddress = peerAddress = op->getTo();
} else {
peerAddress = op->get_from();
localAddress = op->get_to();
peerAddress = op->getFrom();
localAddress = op->getTo();
}
shared_ptr<LinphonePrivate::AbstractChatRoom> chatRoom = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->findChatRoom(

View file

@ -207,9 +207,9 @@ void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LinphonePrivat
}else{
const SalErrorInfo *sei;
linphone_error_info_reset(ei);
sei = op->get_error_info();
sei = op->getErrorInfo();
linphone_error_info_from_sal(ei, sei);
sei = op->get_reason_error_info();
sei = op->getReasonErrorInfo();
linphone_error_info_from_sal_reason_ei(ei, sei);
}
}

View file

@ -119,7 +119,7 @@ void linphone_event_cbs_set_notify_response(LinphoneEventCbs *cbs, LinphoneEvent
static void linphone_event_release(LinphoneEvent *lev){
if (lev->op) {
/*this will stop the refresher*/
lev->op->stop_refreshing();
lev->op->stopRefreshing();
}
linphone_event_unref(lev);
}
@ -133,7 +133,7 @@ static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscri
lev->name=ms_strdup(name);
if (strcmp(lev->name, "conference") == 0)
lev->internal = TRUE;
lev->op->set_user_pointer(lev);
lev->op->setUserPointer(lev);
return lev;
}
@ -221,7 +221,7 @@ LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){
LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event, expires);
linphone_configure_op(lc,lev->op,resource,NULL,TRUE);
lev->op->set_manual_refresher_mode(!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1));
lev->op->setManualRefresherMode(!lp_config_get_int(lc->config,"sip","refresh_generic_subscribe",1));
return lev;
}
@ -229,7 +229,7 @@ LinphoneEvent *linphone_core_create_notify(LinphoneCore *lc, const LinphoneAddre
LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionIncoming, event, -1);
linphone_configure_op(lc,lev->op,resource,NULL,TRUE);
lev->subscription_state = LinphoneSubscriptionIncomingReceived;
lev->op->set_event(event);
lev->op->setEvent(event);
lev->is_out_of_dialog_op = TRUE;
return lev;
}
@ -265,10 +265,10 @@ LinphoneStatus linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneC
}
if (lev->send_custom_headers){
lev->op->set_sent_custom_header(lev->send_custom_headers);
lev->op->setSentCustomHeaders(lev->send_custom_headers);
sal_custom_header_free(lev->send_custom_headers);
lev->send_custom_headers=NULL;
}else lev->op->set_sent_custom_header(NULL);
}else lev->op->setSentCustomHeaders(NULL);
body_handler = sal_body_handler_from_content(body);
auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
@ -324,7 +324,7 @@ LinphoneStatus linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *
ms_error("linphone_event_notify(): cannot notify if not an incoming subscription.");
return -1;
}
body_handler = sal_body_handler_from_content(body);
body_handler = sal_body_handler_from_content(body, false);
auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
return subscribeOp->notify(body_handler);
}
@ -347,7 +347,7 @@ static LinphoneEvent *_linphone_core_create_publish(LinphoneCore *core, Linphone
lev = linphone_event_new_with_op(lc, new SalPublishOp(lc->sal), LinphoneSubscriptionInvalidDir, event);
lev->expires = expires;
linphone_configure_op_with_proxy(lc,lev->op,resource,NULL, !!lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0),cfg);
lev->op->set_manual_refresher_mode(!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1));
lev->op->setManualRefresherMode(!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1));
return lev;
}
LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
@ -374,10 +374,10 @@ static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneConten
return -1;
}
if (lev->send_custom_headers){
lev->op->set_sent_custom_header(lev->send_custom_headers);
lev->op->setSentCustomHeaders(lev->send_custom_headers);
sal_custom_header_free(lev->send_custom_headers);
lev->send_custom_headers=NULL;
}else lev->op->set_sent_custom_header(NULL);
}else lev->op->setSentCustomHeaders(NULL);
body_handler = sal_body_handler_from_content(body);
auto publishOp = dynamic_cast<SalPublishOp *>(lev->op);
err=publishOp->publish(NULL,NULL,lev->name,lev->expires,body_handler);
@ -413,7 +413,7 @@ LinphoneStatus linphone_event_refresh_publish(LinphoneEvent *lev) {
return lev->op->refresh();
}
void linphone_event_pause_publish(LinphoneEvent *lev) {
if (lev->op) lev->op->stop_refreshing();
if (lev->op) lev->op->stopRefreshing();
}
void linphone_event_unpublish(LinphoneEvent *lev) {
lev->terminating = TRUE; /* needed to get clear event*/
@ -435,7 +435,7 @@ void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const
}
const char* linphone_event_get_custom_header(LinphoneEvent* ev, const char* name){
const SalCustomHeader *ch=ev->op->get_recv_custom_header();
const SalCustomHeader *ch=ev->op->getRecvCustomHeaders();
return sal_custom_header_find(ch,name);
}
@ -453,7 +453,7 @@ void linphone_event_terminate(LinphoneEvent *lev){
lev->terminating=TRUE;
if (lev->dir==LinphoneSubscriptionIncoming){
auto op = dynamic_cast<SalSubscribeOp *>(lev->op);
op->close_notify();
op->closeNotify();
}else if (lev->dir==LinphoneSubscriptionOutgoing){
auto op = dynamic_cast<SalSubscribeOp *>(lev->op);
op->unsubscribe();
@ -511,7 +511,7 @@ const char *linphone_event_get_name(const LinphoneEvent *lev){
static const LinphoneAddress *_linphone_event_cache_to (const LinphoneEvent *lev) {
if (lev->to_address)
linphone_address_unref(lev->to_address);
char *buf = sal_address_as_string(lev->op->get_to_address());
char *buf = sal_address_as_string(lev->op->getToAddress());
((LinphoneEvent *)lev)->to_address = linphone_address_new(buf);
ms_free(buf);
return lev->to_address;
@ -520,7 +520,7 @@ static const LinphoneAddress *_linphone_event_cache_to (const LinphoneEvent *lev
static const LinphoneAddress *_linphone_event_cache_from (const LinphoneEvent *lev) {
if (lev->from_address)
linphone_address_unref(lev->from_address);
char *buf = sal_address_as_string(lev->op->get_from_address());
char *buf = sal_address_as_string(lev->op->getFromAddress());
((LinphoneEvent *)lev)->from_address = linphone_address_new(buf);
ms_free(buf);
return lev->from_address;
@ -529,7 +529,7 @@ static const LinphoneAddress *_linphone_event_cache_from (const LinphoneEvent *l
static const LinphoneAddress *_linphone_event_cache_remote_contact (const LinphoneEvent *lev) {
if (lev->remote_contact_address)
linphone_address_unref(lev->remote_contact_address);
char *buf = sal_address_as_string(lev->op->get_remote_contact_address());
char *buf = sal_address_as_string(lev->op->getRemoteContactAddress());
((LinphoneEvent *)lev)->remote_contact_address = linphone_address_new(buf);
ms_free(buf);
return lev->remote_contact_address;

View file

@ -439,3 +439,7 @@ void linphone_factory_set_log_collection_path(LinphoneFactory *factory, const ch
void linphone_factory_enable_log_collection(LinphoneFactory *factory, LinphoneLogCollectionState state) {
linphone_core_enable_log_collection(state);
}
LinphoneTunnelConfig *linphone_factory_create_tunnel_config(LinphoneFactory *factory) {
return linphone_tunnel_config_new();
}

View file

@ -478,7 +478,7 @@ void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence)
}
for(elem=lf->insubs; elem!=NULL; elem=bctbx_list_next(elem)){
auto op = reinterpret_cast<SalPresenceOp *>(bctbx_list_get_data(elem));
op->notify_presence((SalPresenceModel *)presence);
op->notifyPresence((SalPresenceModel *)presence);
}
}
@ -531,7 +531,7 @@ void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
}
static void close_presence_notification(SalPresenceOp *op) {
op->notify_presence_close();
op->notifyPresenceClose();
}
static void release_sal_op(SalOp *op) {
@ -773,7 +773,7 @@ void linphone_friend_update_subscribes(LinphoneFriend *fr, bool_t only_when_regi
linphone_friend_unsubscribe(fr);
}else if (!can_subscribe && fr->outsub){
fr->subscribe_active=FALSE;
fr->outsub->stop_refreshing();
fr->outsub->stopRefreshing();
}
}
@ -1779,11 +1779,13 @@ const char * linphone_friend_phone_number_to_sip_uri(LinphoneFriend *lf, const c
if(strcmp(normalized_number, phone_number) != 0) {
char *old_uri = ms_strdup_printf("sip:%s@%s;user=phone", phone_number, linphone_proxy_config_get_domain(proxy_config));
bctbx_iterator_t *it = bctbx_map_cchar_find_key(lf->friend_list->friends_map_uri, old_uri);
if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(lf->friend_list->friends_map_uri))){
bctbx_iterator_t *end = bctbx_map_cchar_end(lf->friend_list->friends_map_uri);
if (!bctbx_iterator_cchar_equals(it, end)){
linphone_friend_unref((LinphoneFriend*)bctbx_pair_cchar_get_second(bctbx_iterator_cchar_get_pair(it)));
bctbx_map_cchar_erase(lf->friend_list->friends_map_uri, it);
}
bctbx_iterator_cchar_delete(it);
bctbx_iterator_cchar_delete(end);
ms_free(old_uri);
}

View file

@ -577,6 +577,7 @@ LinphoneFriendListStatus linphone_friend_list_import_friend(LinphoneFriendList *
}
iterator = bctbx_list_next(iterator);
}
bctbx_list_free(phone_numbers);
addresses = linphone_friend_get_addresses(lf);
iterator = (bctbx_list_t *)addresses;
@ -799,15 +800,19 @@ LinphoneFriend * linphone_friend_list_find_friend_by_uri(const LinphoneFriendLis
return result;
}
LinphoneFriend * linphone_friend_list_find_friend_by_ref_key(const LinphoneFriendList *list, const char *ref_key) {
if(list) {
bctbx_iterator_t* it = bctbx_map_cchar_find_key(list->friends_map, ref_key);
if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(list->friends_map))) {
LinphoneFriend *linphone_friend_list_find_friend_by_ref_key (const LinphoneFriendList *list, const char *ref_key) {
LinphoneFriend *result = NULL;
if (list) {
bctbx_iterator_t *it = bctbx_map_cchar_find_key(list->friends_map, ref_key);
bctbx_iterator_t *end = bctbx_map_cchar_end(list->friends_map);
if (!bctbx_iterator_cchar_equals(it, end)) {
bctbx_pair_t *pair = bctbx_iterator_cchar_get_pair(it);
return (LinphoneFriend *)bctbx_pair_cchar_get_second(pair);
result = (LinphoneFriend *)bctbx_pair_cchar_get_second(pair);
}
bctbx_iterator_cchar_delete(end);
bctbx_iterator_cchar_delete(it);
}
return NULL;
return result;
}
LinphoneFriend * linphone_friend_list_find_friend_by_inc_subscribe (
@ -829,7 +834,7 @@ LinphoneFriend * linphone_friend_list_find_friend_by_out_subscribe (
const bctbx_list_t *elem;
for (elem = list->friends; elem != NULL; elem = bctbx_list_next(elem)) {
LinphoneFriend *lf = (LinphoneFriend *)bctbx_list_get_data(elem);
if (lf->outsub && ((lf->outsub == op) || lf->outsub->is_forked_of(op))) return lf;
if (lf->outsub && ((lf->outsub == op) || lf->outsub->isForkedOf(op))) return lf;
}
return NULL;
}

View file

@ -317,7 +317,7 @@ static int lime_deriveKey(limeKey_t *key) {
return LIME_UNABLE_TO_DERIVE_KEY;
}
/* Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||0x00000100)*/
/* Derivation is made derived Key = HMAC_SHA256(Key, 0x0000001||"MessageKey"||0x00||SessionId||SessionIndex||0x00000100)*/
/* total data to be hashed is 55 bytes : 4 + 10 + 1 + 32 + 4 + 4 */
inputData[0] = 0x00;
inputData[1] = 0x00;
@ -485,6 +485,9 @@ int lime_createMultipartMessage(void *cachedb, const char *contentType, uint8_t
if (bzrtp_getSelfZID(cachedb, selfURI, selfZid, NULL) != 0) {
return LIME_UNABLE_TO_ENCRYPT_MESSAGE;
}
if (message == NULL || contentType == NULL) {
return LIME_UNABLE_TO_ENCRYPT_MESSAGE;
}
/* encrypted message length is plaintext + 16 for tag */
encryptedMessageLength = (uint32_t)strlen((char *)message) + 16;
@ -802,6 +805,8 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
char *peerUri = NULL;
char *selfUri = NULL;
ms_debug("Content type is known (%s), try to decrypt it", linphone_chat_message_get_content_type(msg));
zrtp_cache_db = linphone_core_get_zrtp_cache_db(lc);
if (zrtp_cache_db == NULL) {
ms_warning("Unable to load content of ZRTP ZID cache to decrypt message");
@ -811,7 +816,7 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
peerUri = linphone_address_as_string_uri_only(linphone_chat_message_get_from_address(msg));
selfUri = linphone_address_as_string_uri_only(linphone_chat_message_get_to_address(msg));
retval = lime_decryptMultipartMessage(zrtp_cache_db, (uint8_t *)linphone_chat_message_get_text(msg), selfUri, peerUri, &decrypted_body, &decrypted_content_type,
bctbx_time_string_to_sec(lp_config_get_string(lc->config, "sip", "lime_key_validity", "0")));
bctbx_time_string_to_sec(lp_config_get_string(lc->config, "sip", "lime_key_validity", "0")));
ms_free(peerUri);
ms_free(selfUri);
if (retval != 0) {
@ -824,9 +829,11 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
linphone_chat_message_set_text(msg, (char *)decrypted_body);
ms_free(decrypted_body);
if (decrypted_content_type != NULL) {
ms_debug("Decrypted content type is ", decrypted_content_type);
linphone_chat_message_set_content_type(msg, decrypted_content_type);
ms_free(decrypted_content_type);
} else {
ms_debug("Decrypted content type is unknown, use plain/text or application/vnd.gsma.rcs-ft-http+xml");
if (strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", linphone_chat_message_get_content_type(msg)) == 0) {
linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml");
} else {
@ -834,6 +841,8 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
}
}
}
} else {
ms_message("Content type is unknown (%s), don't try to decrypt it", linphone_chat_message_get_content_type(msg));
}
return errcode;
}
@ -848,9 +857,9 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEn
if (linphone_chat_message_get_content_type(msg)) {
if (strcmp(linphone_chat_message_get_content_type(msg), "application/vnd.gsma.rcs-ft-http+xml") == 0) {
/* It's a file transfer, content type shall be set to application/cipher.vnd.gsma.rcs-ft-http+xml
TODO: As of january 2017, the content type is now included in the encrypted body, this
application/cipher.vnd.gsma.rcs-ft-http+xml is kept for compatibility with previous versions,
but may be dropped in the future to use xml/cipher instead. */
TODO: As of january 2017, the content type is now included in the encrypted body, this
application/cipher.vnd.gsma.rcs-ft-http+xml is kept for compatibility with previous versions,
but may be dropped in the future to use xml/cipher instead. */
new_content_type = "application/cipher.vnd.gsma.rcs-ft-http+xml";
} else if (strcmp(linphone_chat_message_get_content_type(msg), "application/im-iscomposing+xml") == 0) {
/* We don't encrypt composing messages */
@ -897,50 +906,48 @@ int lime_im_encryption_engine_process_downloading_file_cb(LinphoneImEncryptionEn
LinphoneContent *content = linphone_chat_message_get_file_transfer_information(msg);
if (!content)
return -1;
if (!linphone_content_get_key(content)) {
linphone_content_unref(content);
if (!linphone_content_get_key(content))
return -1;
}
if (!buffer || (size == 0)) {
int result = lime_decryptFile(linphone_content_get_cryptoContext_address(content), NULL, 0, NULL, NULL);
linphone_content_unref(content);
return result;
}
if (!buffer || size == 0)
return lime_decryptFile(linphone_content_get_cryptoContext_address(content), NULL, 0, NULL, NULL);
int result = lime_decryptFile(linphone_content_get_cryptoContext_address(content),
(unsigned char *)linphone_content_get_key(content), size, (char *)decrypted_buffer, (char *)buffer);
linphone_content_unref(content);
return result;
return lime_decryptFile(
linphone_content_get_cryptoContext_address(content),
(unsigned char *)linphone_content_get_key(content),
size,
(char *)decrypted_buffer,
(char *)buffer
);
}
int lime_im_encryption_engine_process_uploading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t *size, uint8_t *encrypted_buffer) {
LinphoneContent *content = linphone_chat_message_get_file_transfer_information(msg);
if (!content)
return -1;
if (!linphone_content_get_key(content)) {
linphone_content_unref(content);
if (!linphone_content_get_key(content))
return -1;
}
if (!buffer || (*size == 0)) {
int result = lime_encryptFile(linphone_content_get_cryptoContext_address(content), NULL, 0, NULL, NULL);
linphone_content_unref(content);
return result;
}
if (!buffer || *size == 0)
return lime_encryptFile(linphone_content_get_cryptoContext_address(content), NULL, 0, NULL, NULL);
size_t file_size = linphone_content_get_size(content);
size_t file_size = linphone_content_get_file_size(content);
if (file_size == 0) {
ms_warning("File size has not been set, encryption will fail if not done in one step (if file is larger than 16K)");
} else if (offset + *size < file_size) {
*size -= (*size % 16);
}
int result = lime_encryptFile(linphone_content_get_cryptoContext_address(content),
(unsigned char *)linphone_content_get_key(content), *size, (char *)buffer, (char *)encrypted_buffer);
linphone_content_unref(content);
return result;
return lime_encryptFile(
linphone_content_get_cryptoContext_address(content),
(unsigned char *)linphone_content_get_key(content),
*size,
(char *)buffer,
(char *)encrypted_buffer
);
}
bool_t lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room) {
@ -954,10 +961,8 @@ void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneImEncryptio
* file_transfer_information->key field of the msg */
sal_get_random_bytes((unsigned char *)keyBuffer, FILE_TRANSFER_KEY_SIZE);
LinphoneContent *content = linphone_chat_message_get_file_transfer_information(msg);
if (!content)
return;
linphone_content_set_key(content, keyBuffer, FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */
linphone_content_unref(content);
if (content)
linphone_content_set_key(content, keyBuffer, FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */
}
#else /* HAVE_LIME */

View file

@ -28,6 +28,7 @@
#include "linphone/core.h"
#include "private.h"
#include "linphone/lpconfig.h"
#include "c-wrapper/c-wrapper.h"
LinphoneTunnel* linphone_core_get_tunnel(const LinphoneCore *lc){
return lc->tunnel;
@ -42,13 +43,13 @@ struct _LinphoneTunnel {
static void _linphone_tunnel_uninit(LinphoneTunnel *tunnel);
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneTunnel);
BELLE_SIP_DECLARE_VPTR(LinphoneTunnel);
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneTunnel);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneTunnel, belle_sip_object_t,
_linphone_tunnel_uninit, // uninit
NULL, // clone
NULL, // marshal
FALSE // unowned
)
);
extern "C" LinphoneTunnel* linphone_core_tunnel_new(LinphoneCore *lc){
LinphoneTunnel* tunnel = belle_sip_object_new(LinphoneTunnel);
@ -231,13 +232,13 @@ static void linphone_tunnel_add_server_intern(LinphoneTunnel *tunnel, LinphoneTu
linphone_tunnel_config_get_port(tunnel_config),
linphone_tunnel_config_get_host2(tunnel_config),
linphone_tunnel_config_get_port2(tunnel_config),
linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config),
linphone_tunnel_config_get_delay(tunnel_config));
(unsigned int)linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config),
(unsigned int)linphone_tunnel_config_get_delay(tunnel_config));
} else {
bcTunnel(tunnel)->addServer(linphone_tunnel_config_get_host(tunnel_config),
linphone_tunnel_config_get_port(tunnel_config),
linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config),
linphone_tunnel_config_get_delay(tunnel_config));
(unsigned int)linphone_tunnel_config_get_remote_udp_mirror_port(tunnel_config),
(unsigned int)linphone_tunnel_config_get_delay(tunnel_config));
}
} else if (linphone_tunnel_config_get_host2(tunnel_config) != NULL) {
bcTunnel(tunnel)->addServerPair(linphone_tunnel_config_get_host(tunnel_config),

View file

@ -860,7 +860,7 @@ static void process_response_from_post_file_log_collection(void *data, const bel
cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */
while (cur != NULL) {
if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) {
file_url = xmlGetProp(cur, (const xmlChar *)"url");
file_url = xmlGetProp(cur, (const xmlChar *)"url");
}
cur=cur->next;
}
@ -874,7 +874,9 @@ static void process_response_from_post_file_log_collection(void *data, const bel
}
if (file_url != NULL) {
linphone_core_notify_log_collection_upload_state_changed(core, LinphoneCoreLogCollectionUploadStateDelivered, (const char *)file_url);
xmlFree(file_url);
}
xmlFreeDoc(xmlMessageBody);
clean_log_collection_upload_context(core);
} else {
ms_error("Unexpected HTTP response code %i during log collection upload to %s", code, linphone_core_get_log_collection_upload_server_url(core));
@ -1277,11 +1279,15 @@ static void certificates_config_read(LinphoneCore *lc) {
char *root_ca_path = bctbx_strdup_printf("%s/rootca.pem", data_dir);
const char *rootca = lp_config_get_string(lc->config,"sip","root_ca", NULL);
// If rootca is not existing anymore, we reset it to the default value
if (rootca == NULL || (bctbx_file_exist(rootca) != 0)) {
if (rootca == NULL || ((bctbx_file_exist(rootca) != 0) && (!bctbx_directory_exists(rootca)))) {
#ifdef __linux
struct stat sb;
if (stat("/etc/ssl/certs", &sb) == 0 && S_ISDIR(sb.st_mode)) {
rootca = "/etc/ssl/certs";
#ifdef __ANDROID__
const char *possible_rootca = "/system/etc/security/cacerts";
#else
const char *possible_rootca = "/etc/ssl/certs";
#endif
if (bctbx_directory_exists(possible_rootca)) {
rootca = possible_rootca;
} else
#endif
{
@ -1304,12 +1310,12 @@ static void sip_config_read(LinphoneCore *lc) {
int ipv6_default = TRUE;
if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){
lc->sal->use_session_timers(200);
lc->sal->useSessionTimers(200);
}
lc->sal->use_no_initial_route(!!lp_config_get_int(lc->config,"sip","use_no_initial_route",0));
lc->sal->use_rport(!!lp_config_get_int(lc->config,"sip","use_rport",1));
lc->sal->set_contact_linphone_specs(lp_config_get_string(lc->config, "sip", "linphone_specs", NULL));
lc->sal->useNoInitialRoute(!!lp_config_get_int(lc->config,"sip","use_no_initial_route",0));
lc->sal->useRport(!!lp_config_get_int(lc->config,"sip","use_rport",1));
lc->sal->setContactLinphoneSpecs(lp_config_get_string(lc->config, "sip", "linphone_specs", NULL));
if (!lp_config_get_int(lc->config,"sip","ipv6_migration_done",FALSE) && lp_config_has_entry(lc->config,"sip","use_ipv6")) {
lp_config_clean_entry(lc->config,"sip","use_ipv6");
@ -1328,7 +1334,7 @@ static void sip_config_read(LinphoneCore *lc) {
certificates_config_read(lc);
/*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/
lc->sal->set_dscp(linphone_core_get_sip_dscp(lc));
lc->sal->setDscp(linphone_core_get_sip_dscp(lc));
/*start listening on ports*/
linphone_core_set_sip_transports(lc,&tr);
@ -1394,7 +1400,7 @@ static void sip_config_read(LinphoneCore *lc) {
linphone_core_set_media_encryption(lc,linphone_core_get_media_encryption(lc));
/*enable the reconnection to the primary server when it is up again asap*/
lc->sal->enable_reconnect_to_primary_asap(!!lp_config_get_int(lc->config,"sip","reconnect_to_primary_asap",0));
lc->sal->enableReconnectToPrimaryAsap(!!lp_config_get_int(lc->config,"sip","reconnect_to_primary_asap",0));
/*for tuning or test*/
lc->sip_conf.sdp_200_ack = !!lp_config_get_int(lc->config,"sip","sdp_200_ack",0);
@ -1407,12 +1413,12 @@ static void sip_config_read(LinphoneCore *lc) {
lc->sip_conf.keepalive_period = (unsigned int)lp_config_get_int(lc->config,"sip","keepalive_period",10000);
lc->sip_conf.tcp_tls_keepalive = !!lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0);
linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
lc->sal->use_one_matching_codec_policy(!!lp_config_get_int(lc->config,"sip","only_one_codec",0));
lc->sal->use_dates(!!lp_config_get_int(lc->config,"sip","put_date",0));
lc->sal->enable_sip_update_method(!!lp_config_get_int(lc->config,"sip","sip_update",1));
lc->sal->useOneMatchingCodecPolicy(!!lp_config_get_int(lc->config,"sip","only_one_codec",0));
lc->sal->useDates(!!lp_config_get_int(lc->config,"sip","put_date",0));
lc->sal->enableSipUpdateMethod(!!lp_config_get_int(lc->config,"sip","sip_update",1));
lc->sip_conf.vfu_with_info = !!lp_config_get_int(lc->config,"sip","vfu_with_info",1);
linphone_core_set_sip_transport_timeout(lc, lp_config_get_int(lc->config, "sip", "transport_timeout", 63000));
lc->sal->set_supported_tags(lp_config_get_string(lc->config,"sip","supported","replaces, outbound, gruu"));
lc->sal->setSupportedTags(lp_config_get_string(lc->config,"sip","supported","replaces, outbound, gruu"));
lc->sip_conf.save_auth_info = !!lp_config_get_int(lc->config, "sip", "save_auth_info", 1);
linphone_core_create_im_notif_policy(lc);
}
@ -1470,8 +1476,10 @@ static void rtp_config_read(LinphoneCore *lc) {
linphone_core_set_avpf_mode(lc,static_cast<LinphoneAVPFMode>(lp_config_get_int(lc->config,"rtp","avpf",LinphoneAVPFDisabled)));
if ((tmp=lp_config_get_string(lc->config,"rtp","audio_multicast_addr",NULL)))
linphone_core_set_audio_multicast_addr(lc,tmp);
else
else {
if (lc->rtp_conf.audio_multicast_addr) bctbx_free(lc->rtp_conf.audio_multicast_addr);
lc->rtp_conf.audio_multicast_addr=ms_strdup("224.1.2.3");
}
if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_enabled",-1)) >-1)
linphone_core_enable_audio_multicast(lc, !!tmp_int);
if ((tmp_int=lp_config_get_int(lc->config,"rtp","audio_multicast_ttl",-1))>0)
@ -1480,8 +1488,10 @@ static void rtp_config_read(LinphoneCore *lc) {
lc->rtp_conf.audio_multicast_ttl=1;/*local network*/
if ((tmp=lp_config_get_string(lc->config,"rtp","video_multicast_addr",NULL)))
linphone_core_set_video_multicast_addr(lc,tmp);
else
else {
if (lc->rtp_conf.video_multicast_addr) bctbx_free(lc->rtp_conf.video_multicast_addr);
lc->rtp_conf.video_multicast_addr=ms_strdup("224.1.2.3");
}
if ((tmp_int=lp_config_get_int(lc->config,"rtp","video_multicast_ttl",-1))>-1)
linphone_core_set_video_multicast_ttl(lc,tmp_int);
else
@ -1607,10 +1617,9 @@ static SalStreamType payload_type_get_stream_type(const PayloadType *pt){
/*this function merges the payload types from the codec default list with the list read from configuration file.
* If a new codec becomes supported in Liblinphone or if the list from configuration file is empty or incomplete, all the supported codecs are added
* automatically. This 'l' list is entirely destroyed and rewritten.*/
* automatically. This 'l' list is entirely rewritten.*/
static bctbx_list_t *add_missing_supported_codecs(LinphoneCore *lc, const bctbx_list_t *default_list, bctbx_list_t *l){
const bctbx_list_t *elem;
bctbx_list_t *newlist;
PayloadType *last_seen = NULL;
for(elem=default_list; elem!=NULL; elem=elem->next){
@ -1633,41 +1642,33 @@ static bctbx_list_t *add_missing_supported_codecs(LinphoneCore *lc, const bctbx_
last_seen = (PayloadType*)elem2->data;
}
}
newlist=bctbx_list_copy_with_data(l,(void *(*)(void*))payload_type_clone);
bctbx_list_free(l);
return newlist;
return l;
}
/*
* This function adds missing codecs, if required by configuration.
* This 'l' list is entirely destroyed and a new list is returned.
* This 'l' list is entirely rewritten if required.
*/
static bctbx_list_t *handle_missing_codecs(LinphoneCore *lc, const bctbx_list_t *default_list, bctbx_list_t *l, MSFormatType ft){
static bctbx_list_t *handle_missing_codecs (LinphoneCore *lc, const bctbx_list_t *default_list, bctbx_list_t *l, MSFormatType ft) {
const char *name = "unknown";
int add_missing;
bctbx_list_t *ret;
switch(ft){
switch (ft) {
case MSAudio:
name = "add_missing_audio_codecs";
break;
break;
case MSVideo:
name = "add_missing_video_codecs";
break;
break;
case MSText:
name = "add_missing_text_codecs";
break;
break;
case MSUnknownMedia:
break;
}
add_missing = lp_config_get_int(lc->config, "misc", name, 1);
if (add_missing){
ret = add_missing_supported_codecs(lc, default_list, l);
}else{
ret = bctbx_list_copy_with_data(l,(void *(*)(void*))payload_type_clone);
bctbx_list_free(l);
}
return ret;
if (lp_config_get_int(lc->config, "misc", name, 1))
return add_missing_supported_codecs(lc, default_list, l);
return l;
}
static bctbx_list_t *codec_append_if_new(bctbx_list_t *l, PayloadType *pt){
@ -1864,13 +1865,13 @@ void linphone_core_set_expected_bandwidth(LinphoneCore *lc, int bw){
}
void linphone_core_set_sip_transport_timeout(LinphoneCore *lc, int timeout_ms) {
lc->sal->set_transport_timeout(timeout_ms);
lc->sal->setTransportTimeout(timeout_ms);
if (linphone_core_ready(lc))
lp_config_set_int(lc->config, "sip", "transport_timeout", timeout_ms);
}
int linphone_core_get_sip_transport_timeout(LinphoneCore *lc) {
return lc->sal->get_transport_timeout();
return lc->sal->getTransportTimeout();
}
bool_t linphone_core_get_dns_set_by_app(LinphoneCore *lc) {
@ -1883,27 +1884,27 @@ void linphone_core_set_dns_servers_app(LinphoneCore *lc, const bctbx_list_t *ser
}
void linphone_core_set_dns_servers(LinphoneCore *lc, const bctbx_list_t *servers){
lc->sal->set_dns_servers(servers);
lc->sal->setDnsServers(servers);
}
void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enable) {
lc->sal->enable_dns_srv(enable);
lc->sal->enableDnsSrv(enable);
if (linphone_core_ready(lc))
lp_config_set_int(lc->config, "net", "dns_srv_enabled", enable ? 1 : 0);
}
bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc) {
return lc->sal->dns_srv_enabled();
return lc->sal->dnsSrvEnabled();
}
void linphone_core_enable_dns_search(LinphoneCore *lc, bool_t enable) {
lc->sal->enable_dns_search(enable);
lc->sal->enableDnsSearch(enable);
if (linphone_core_ready(lc))
lp_config_set_int(lc->config, "net", "dns_search_enabled", enable ? 1 : 0);
}
bool_t linphone_core_dns_search_enabled(const LinphoneCore *lc) {
return lc->sal->dns_search_enabled();
return lc->sal->dnsSearchEnabled();
}
int linphone_core_get_download_bandwidth(const LinphoneCore *lc){
@ -1979,12 +1980,15 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const
linphone_core_notify_global_state_changed(lc,gstate,message);
}
static void misc_config_read(LinphoneCore *lc) {
LpConfig *config=lc->config;
static void misc_config_read (LinphoneCore *lc) {
LpConfig *config = lc->config;
lc->max_call_logs = lp_config_get_int(config,"misc","history_max_size",LINPHONE_MAX_CALL_HISTORY_SIZE);
lc->max_calls = lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS);
if (lc->user_certificates_path) bctbx_free(lc->user_certificates_path);
lc->user_certificates_path = bctbx_strdup(lp_config_get_string(config, "misc", "user_certificates_path", "."));
lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",LINPHONE_MAX_CALL_HISTORY_SIZE);
lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS);
lc->user_certificates_path=ms_strdup(lp_config_get_string(config,"misc","user_certificates_path","."));
lc->send_call_stats_periodical_updates = !!lp_config_get_int(config, "misc", "send_call_stats_periodical_updates", 0);
}
@ -2248,12 +2252,12 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
image_resources_dir = linphone_factory_get_image_resources_dir(lfactory);
lc->sal=new Sal(NULL);
lc->sal->set_refresher_retry_after(lp_config_get_int(lc->config, "sip", "refresher_retry_after", 60000));
lc->sal->set_http_proxy_host(linphone_core_get_http_proxy_host(lc));
lc->sal->set_http_proxy_port(linphone_core_get_http_proxy_port(lc));
lc->sal->setRefresherRetryAfter(lp_config_get_int(lc->config, "sip", "refresher_retry_after", 60000));
lc->sal->setHttpProxyHost(linphone_core_get_http_proxy_host(lc));
lc->sal->setHttpProxyPort(linphone_core_get_http_proxy_port(lc));
lc->sal->set_user_pointer(lc);
lc->sal->set_callbacks(&linphone_sal_callbacks);
lc->sal->setUserPointer(lc);
lc->sal->setCallbacks(&linphone_sal_callbacks);
#ifdef __ANDROID__
if (system_context)
@ -2264,7 +2268,7 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
// MS Factory MUST be created after Android has been set, otherwise no camera will be detected !
lc->factory = ms_factory_new_with_voip_and_directories(msplugins_dir, image_resources_dir);
lc->sal->set_factory(lc->factory);
lc->sal->setFactory(lc->factory);
belr::GrammarLoader::get().addPath(getPlatformHelpers(lc)->getDataPath());
@ -2304,11 +2308,11 @@ static void linphone_core_init(LinphoneCore * lc, LinphoneCoreCbs *cbs, LpConfig
/* Create the http provider in dual stack mode (ipv4 and ipv6.
* If this creates problem, we may need to implement parallel ipv6/ ipv4 http requests in belle-sip.
*/
lc->http_provider = belle_sip_stack_create_http_provider(reinterpret_cast<belle_sip_stack_t *>(lc->sal->get_stack_impl()), "::0");
lc->http_provider = belle_sip_stack_create_http_provider(reinterpret_cast<belle_sip_stack_t *>(lc->sal->getStackImpl()), "::0");
lc->http_crypto_config = belle_tls_crypto_config_new();
belle_http_provider_set_tls_crypto_config(lc->http_provider,lc->http_crypto_config);
certificates_config_read(lc);
//certificates_config_read(lc); // This will be done below in _linphone_core_read_config()
lc->ringtoneplayer = linphone_ringtoneplayer_new();
@ -2342,13 +2346,13 @@ void linphone_core_start (LinphoneCore *lc) {
const char* uuid=lp_config_get_string(lc->config,"misc","uuid",NULL);
if (!uuid){
char tmp[64];
lc->sal->create_uuid(tmp,sizeof(tmp));
lc->sal->createUuid(tmp,sizeof(tmp));
lp_config_set_string(lc->config,"misc","uuid",tmp);
}else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/
lc->sal->set_uuid(uuid);
lc->sal->setUuid(uuid);
if (lc->sal->get_root_ca()) {
belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, lc->sal->get_root_ca());
if (lc->sal->getRootCa()) {
belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, lc->sal->getRootCa());
belle_http_provider_set_tls_crypto_config(lc->http_provider, lc->http_crypto_config);
}
@ -2548,8 +2552,8 @@ void linphone_core_enable_lime(LinphoneCore *lc, LinphoneLimeState val){
LinphoneImEncryptionEngine *imee = linphone_im_encryption_engine_new();
LinphoneImEncryptionEngineCbs *cbs = linphone_im_encryption_engine_get_callbacks(imee);
if(lime_is_available()){
if (linphone_core_ready(lc)){
if (lime_is_available()) {
if (linphone_core_ready(lc)) {
lp_config_set_int(lc->config,"sip","lime",val);
}
@ -2878,12 +2882,12 @@ void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char
char ua_string[256];
snprintf(ua_string, sizeof(ua_string) - 1, "%s/%s", name?name:"", ver?ver:"");
if (lc->sal) {
lc->sal->set_user_agent(ua_string);
lc->sal->append_stack_string_to_user_agent();
lc->sal->setUserAgent(ua_string);
lc->sal->appendStackStringToUserAgent();
}
}
const char *linphone_core_get_user_agent(LinphoneCore *lc){
return lc->sal->get_user_agent();
return lc->sal->getUserAgent();
}
const char *linphone_core_get_user_agent_name(void){
@ -2926,32 +2930,32 @@ int _linphone_core_apply_transports(LinphoneCore *lc){
else
anyaddr="0.0.0.0";
sal->unlisten_ports();
sal->unlistenPorts();
listening_address = lp_config_get_string(lc->config,"sip","bind_address",anyaddr);
if (linphone_core_get_http_proxy_host(lc)) {
sal->set_http_proxy_host(linphone_core_get_http_proxy_host(lc));
sal->set_http_proxy_port(linphone_core_get_http_proxy_port(lc));
sal->setHttpProxyHost(linphone_core_get_http_proxy_host(lc));
sal->setHttpProxyPort(linphone_core_get_http_proxy_port(lc));
}
if (lc->tunnel && linphone_tunnel_sip_enabled(lc->tunnel) && linphone_tunnel_get_activated(lc->tunnel)){
sal->set_listen_port(anyaddr,tr->udp_port,SalTransportUDP,TRUE);
sal->setListenPort(anyaddr,tr->udp_port,SalTransportUDP,TRUE);
}else{
if (tr->udp_port!=0){
sal->set_listen_port(listening_address,tr->udp_port,SalTransportUDP,FALSE);
sal->setListenPort(listening_address,tr->udp_port,SalTransportUDP,FALSE);
}
if (tr->tcp_port!=0){
sal->set_listen_port (listening_address,tr->tcp_port,SalTransportTCP,FALSE);
sal->setListenPort (listening_address,tr->tcp_port,SalTransportTCP,FALSE);
}
if (linphone_core_sip_transport_supported(lc,LinphoneTransportTls)){
if (tr->tls_port!=0)
sal->set_listen_port (listening_address,tr->tls_port,SalTransportTLS,FALSE);
sal->setListenPort (listening_address,tr->tls_port,SalTransportTLS,FALSE);
}
}
return 0;
}
bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp){
return !!lc->sal->transport_available((SalTransport)tp);
return !!lc->sal->isTransportAvailable((SalTransport)tp);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneTransports);
@ -3091,17 +3095,17 @@ LinphoneTransports *linphone_core_get_transports(LinphoneCore *lc){
}
void linphone_core_get_sip_transports_used(LinphoneCore *lc, LinphoneSipTransports *tr){
tr->udp_port=lc->sal->get_listening_port(SalTransportUDP);
tr->tcp_port=lc->sal->get_listening_port(SalTransportTCP);
tr->tls_port=lc->sal->get_listening_port(SalTransportTLS);
tr->udp_port=lc->sal->getListeningPort(SalTransportUDP);
tr->tcp_port=lc->sal->getListeningPort(SalTransportTCP);
tr->tls_port=lc->sal->getListeningPort(SalTransportTLS);
}
LinphoneTransports *linphone_core_get_transports_used(LinphoneCore *lc){
LinphoneTransports *transports = linphone_transports_new();
transports->udp_port = lc->sal->get_listening_port(SalTransportUDP);
transports->tcp_port = lc->sal->get_listening_port(SalTransportTCP);
transports->tls_port = lc->sal->get_listening_port(SalTransportTLS);
transports->dtls_port = lc->sal->get_listening_port(SalTransportDTLS);
transports->udp_port = lc->sal->getListeningPort(SalTransportUDP);
transports->tcp_port = lc->sal->getListeningPort(SalTransportTCP);
transports->tls_port = lc->sal->getListeningPort(SalTransportTLS);
transports->dtls_port = lc->sal->getListeningPort(SalTransportDTLS);
return transports;
}
@ -3133,7 +3137,7 @@ void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){
bool_t linphone_core_content_encoding_supported(const LinphoneCore *lc, const char *content_encoding) {
const char *handle_content_encoding = lp_config_get_string(lc->config, "sip", "handle_content_encoding", "deflate");
return (strcmp(handle_content_encoding, content_encoding) == 0) && lc->sal->content_encoding_available(content_encoding);
return (strcmp(handle_content_encoding, content_encoding) == 0) && lc->sal->isContentEncodingAvailable(content_encoding);
}
static void monitor_network_state(LinphoneCore *lc, time_t curtime){
@ -3544,7 +3548,7 @@ static void linphone_transfer_routes_to_op(bctbx_list_t *routes, SalOp *op){
bctbx_list_t *it;
for(it=routes;it!=NULL;it=it->next){
SalAddress *addr=(SalAddress*)it->data;
op->add_route_address(addr);
op->addRouteAddress(addr);
sal_address_destroy(addr);
}
bctbx_list_free(routes);
@ -3557,7 +3561,7 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon
if (proxy){
identity=linphone_proxy_config_get_identity(proxy);
if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) {
op->set_privacy(linphone_proxy_config_get_privacy(proxy));
op->setPrivacy(linphone_proxy_config_get_privacy(proxy));
}
}else identity=linphone_core_get_primary_contact(lc);
/*sending out of calls*/
@ -3566,21 +3570,21 @@ void linphone_configure_op_with_proxy(LinphoneCore *lc, SalOp *op, const Linphon
linphone_transfer_routes_to_op(routes,op);
}
op->set_to_address(L_GET_PRIVATE_FROM_C_OBJECT(dest)->getInternalAddress());
op->set_from(identity);
op->set_sent_custom_header(headers);
op->set_realm(linphone_proxy_config_get_realm(proxy));
op->setToAddress(L_GET_PRIVATE_FROM_C_OBJECT(dest)->getInternalAddress());
op->setFrom(identity);
op->setSentCustomHeaders(headers);
op->setRealm(linphone_proxy_config_get_realm(proxy));
if (with_contact && proxy && proxy->op){
const LinphoneAddress *contact = linphone_proxy_config_get_contact(proxy);
SalAddress *salAddress = nullptr;
if (contact)
salAddress = sal_address_clone(const_cast<SalAddress *>(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress()));
op->set_contact_address(salAddress);
op->setContactAddress(salAddress);
if (salAddress)
sal_address_unref(salAddress);
}
op->enable_cnx_ip_to_0000_if_sendonly(!!lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/
op->enableCnxIpTo0000IfSendOnly(!!lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/
}
void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact) {
linphone_configure_op_with_proxy(lc, op, dest, headers,with_contact,linphone_core_lookup_known_proxy(lc,dest));
@ -4325,7 +4329,7 @@ const char *linphone_core_get_ring(const LinphoneCore *lc){
}
void linphone_core_set_root_ca(LinphoneCore *lc, const char *path) {
lc->sal->set_root_ca(path);
lc->sal->setRootCa(path);
if (lc->http_crypto_config) {
belle_tls_crypto_config_set_root_ca(lc->http_crypto_config, path);
}
@ -4333,8 +4337,8 @@ void linphone_core_set_root_ca(LinphoneCore *lc, const char *path) {
}
void linphone_core_set_root_ca_data(LinphoneCore *lc, const char *data) {
lc->sal->set_root_ca(NULL);
lc->sal->set_root_ca_data(data);
lc->sal->setRootCa(NULL);
lc->sal->setRootCaData(data);
if (lc->http_crypto_config) {
belle_tls_crypto_config_set_root_ca_data(lc->http_crypto_config, data);
}
@ -4345,7 +4349,7 @@ const char *linphone_core_get_root_ca(LinphoneCore *lc){
}
void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){
lc->sal->verify_server_certificates(yesno);
lc->sal->verifyServerCertificates(yesno);
if (lc->http_crypto_config){
belle_tls_crypto_config_set_verify_exceptions(lc->http_crypto_config, yesno ? 0 : BELLE_TLS_VERIFY_ANY_REASON);
}
@ -4353,7 +4357,7 @@ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){
}
void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){
lc->sal->verify_server_cn(yesno);
lc->sal->verifyServerCn(yesno);
if (lc->http_crypto_config){
belle_tls_crypto_config_set_verify_exceptions(lc->http_crypto_config, yesno ? 0 : BELLE_TLS_VERIFY_CN_MISMATCH);
}
@ -4361,7 +4365,7 @@ void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){
}
void linphone_core_set_ssl_config(LinphoneCore *lc, void *ssl_config) {
lc->sal->set_ssl_config(ssl_config);
lc->sal->setSslConfig(ssl_config);
if (lc->http_crypto_config) {
belle_tls_crypto_config_set_ssl_config(lc->http_crypto_config, ssl_config);
}
@ -4658,9 +4662,9 @@ void linphone_core_set_nat_policy(LinphoneCore *lc, LinphoneNatPolicy *policy) {
linphone_nat_policy_save_to_config(lc->nat_policy);
}
lc->sal->enable_nat_helper(!!lp_config_get_int(lc->config, "net", "enable_nat_helper", 1));
lc->sal->enable_auto_contacts(TRUE);
lc->sal->use_rport(!!lp_config_get_int(lc->config, "sip", "use_rport", 1));
lc->sal->enableNatHelper(!!lp_config_get_int(lc->config, "net", "enable_nat_helper", 1));
lc->sal->enableAutoContacts(TRUE);
lc->sal->useRport(!!lp_config_get_int(lc->config, "sip", "use_rport", 1));
if (lc->sip_conf.contact) update_primary_contact(lc);
}
@ -5865,8 +5869,8 @@ void sip_config_uninit(LinphoneCore *lc)
linphone_vcard_context_destroy(lc->vcard_context);
}
lc->sal->reset_transports();
lc->sal->unlisten_ports(); /*to make sure no new messages are received*/
lc->sal->resetTransports();
lc->sal->unlistenPorts(); /*to make sure no new messages are received*/
if (lc->http_provider) {
belle_sip_object_unref(lc->http_provider);
lc->http_provider=NULL;
@ -5992,9 +5996,9 @@ void _linphone_core_codec_config_write(LinphoneCore *lc){
static void codecs_config_uninit(LinphoneCore *lc)
{
_linphone_core_codec_config_write(lc);
bctbx_list_free_with_data(lc->codecs_conf.audio_codecs, (void (*)(void*))payload_type_destroy);
bctbx_list_free_with_data(lc->codecs_conf.video_codecs, (void (*)(void*))payload_type_destroy);
bctbx_list_free_with_data(lc->codecs_conf.text_codecs, (void (*)(void*))payload_type_destroy);
bctbx_list_free(lc->codecs_conf.audio_codecs);
bctbx_list_free(lc->codecs_conf.video_codecs);
bctbx_list_free(lc->codecs_conf.text_codecs);
}
void friends_config_uninit(LinphoneCore* lc)
@ -6173,7 +6177,7 @@ static void set_sip_network_reachable(LinphoneCore* lc,bool_t is_sip_reachable,
if (!lc->sip_network_reachable){
linphone_core_invalidate_friend_subscriptions(lc);
lc->sal->reset_transports();
lc->sal->resetTransports();
}
}
@ -6238,7 +6242,7 @@ bool_t linphone_core_is_network_reachable(LinphoneCore* lc) {
}
ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc){
return lc->sal->get_socket();
return lc->sal->getSocket();
}
void linphone_core_destroy(LinphoneCore *lc){
@ -6358,15 +6362,15 @@ const char *linphone_error_to_string(LinphoneReason err){
void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) {
if (enable > 0) {
lc->sal->use_tcp_tls_keepalive(lc->sip_conf.tcp_tls_keepalive);
lc->sal->set_keepalive_period(lc->sip_conf.keepalive_period);
lc->sal->useTcpTlsKeepAlive(lc->sip_conf.tcp_tls_keepalive);
lc->sal->setKeepAlivePeriod(lc->sip_conf.keepalive_period);
} else {
lc->sal->set_keepalive_period(0);
lc->sal->setKeepAlivePeriod(0);
}
}
bool_t linphone_core_keep_alive_enabled(LinphoneCore* lc) {
return lc->sal->get_keepalive_period() > 0;
return lc->sal->getKeepAlivePeriod() > 0;
}
void linphone_core_start_dtmf_stream(LinphoneCore* lc) {
@ -6525,7 +6529,7 @@ void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file){
/* clean up */
bctbx_free(bkpFile);
xmlFree(cacheXml);
xmlFreeDoc(cacheXml);
}
bctbx_free(tmpFile);
} else {
@ -6598,12 +6602,11 @@ end:
#endif /* SQLITE_STORAGE_ENABLED */
}
void linphone_core_set_user_certificates_path(LinphoneCore *lc, const char* path){
char* new_value;
new_value = path?ms_strdup(path):NULL;
if (lc->user_certificates_path) ms_free(lc->user_certificates_path);
lp_config_set_string(lc->config,"misc","user_certificates_path",lc->user_certificates_path=new_value);
return ;
void linphone_core_set_user_certificates_path (LinphoneCore *lc, const char *path) {
char *new_value = path ? bctbx_strdup(path) : NULL;
if (lc->user_certificates_path) bctbx_free(lc->user_certificates_path);
lc->user_certificates_path = new_value;
lp_config_set_string(lc->config, "misc", "user_certificates_path", lc->user_certificates_path);
}
const char *linphone_core_get_user_certificates_path(LinphoneCore *lc){
@ -6729,7 +6732,7 @@ const char* linphone_core_get_device_identifier(const LinphoneCore *lc) {
}
void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){
lc->sal->set_dscp(dscp);
lc->sal->setDscp(dscp);
if (linphone_core_ready(lc)){
lp_config_set_int_hex(lc->config,"sip","dscp",dscp);
_linphone_core_apply_transports(lc);
@ -6793,13 +6796,13 @@ const char * linphone_core_get_file_transfer_server(LinphoneCore *core) {
}
void linphone_core_add_supported_tag(LinphoneCore *lc, const char *tag){
lc->sal->add_supported_tag(tag);
lp_config_set_string(lc->config,"sip","supported",lc->sal->get_supported_tags());
lc->sal->addSupportedTag(tag);
lp_config_set_string(lc->config,"sip","supported",lc->sal->getSupportedTags());
}
void linphone_core_remove_supported_tag(LinphoneCore *lc, const char *tag){
lc->sal->remove_supported_tag(tag);
lp_config_set_string(lc->config,"sip","supported",lc->sal->get_supported_tags());
lc->sal->removeSupportedTag(tag);
lp_config_set_string(lc->config,"sip","supported",lc->sal->getSupportedTags());
}
void linphone_core_set_avpf_mode(LinphoneCore *lc, LinphoneAVPFMode mode){
@ -6927,15 +6930,15 @@ void linphone_core_enable_realtime_text(LinphoneCore *lc, bool_t value) {
void linphone_core_set_http_proxy_host(LinphoneCore *lc, const char *host) {
lp_config_set_string(lc->config,"sip","http_proxy_host",host);
if (lc->sal) {
lc->sal->set_http_proxy_host(host);
lc->sal->set_http_proxy_port(linphone_core_get_http_proxy_port(lc)); /*to make sure default value is set*/
lc->sal->setHttpProxyHost(host);
lc->sal->setHttpProxyPort(linphone_core_get_http_proxy_port(lc)); /*to make sure default value is set*/
}
}
void linphone_core_set_http_proxy_port(LinphoneCore *lc, int port) {
lp_config_set_int(lc->config,"sip","http_proxy_port",port);
if (lc->sal)
lc->sal->set_http_proxy_port(port);
lc->sal->setHttpProxyPort(port);
}
const char *linphone_core_get_http_proxy_host(const LinphoneCore *lc) {
@ -7181,19 +7184,23 @@ LinphoneImEncryptionEngine *linphone_core_get_im_encryption_engine(const Linphon
}
void linphone_core_initialize_supported_content_types(LinphoneCore *lc) {
lc->sal->add_content_type_support("text/plain");
lc->sal->add_content_type_support("message/external-body");
lc->sal->add_content_type_support("application/vnd.gsma.rcs-ft-http+xml");
lc->sal->add_content_type_support("application/im-iscomposing+xml");
lc->sal->add_content_type_support("message/imdn+xml");
lc->sal->addContentTypeSupport("text/plain");
lc->sal->addContentTypeSupport("message/external-body");
lc->sal->addContentTypeSupport("application/vnd.gsma.rcs-ft-http+xml");
lc->sal->addContentTypeSupport("application/im-iscomposing+xml");
lc->sal->addContentTypeSupport("message/imdn+xml");
}
bool_t linphone_core_is_content_type_supported(const LinphoneCore *lc, const char *content_type) {
return lc->sal->is_content_type_supported(content_type);
return lc->sal->isContentTypeSupported(content_type);
}
void linphone_core_add_content_type_support(LinphoneCore *lc, const char *content_type) {
lc->sal->add_content_type_support(content_type);
lc->sal->addContentTypeSupport(content_type);
}
void linphone_core_remove_content_type_support(LinphoneCore *lc, const char *content_type) {
lc->sal->removeContentTypeSupport(content_type);
}
#ifdef ENABLE_UPDATE_CHECK
@ -7351,5 +7358,5 @@ const char *linphone_core_get_linphone_specs (const LinphoneCore *core) {
void linphone_core_set_linphone_specs (LinphoneCore *core, const char *specs) {
lp_config_set_string(linphone_core_get_config(core), "sip", "linphone_specs", specs);
core->sal->set_contact_linphone_specs(specs);
core->sal->setContactLinphoneSpecs(specs);
}

View file

@ -88,7 +88,6 @@ static int _local_player_get_current_position(LinphonePlayer *obj) {
static void _local_player_destroy(LinphonePlayer *obj) {
ms_media_player_free((MSMediaPlayer *)obj->impl);
_linphone_player_destroy(obj);
}
static void _local_player_close(LinphonePlayer *obj) {

View file

@ -127,6 +127,7 @@ static void _log_handler_on_message_written_cb(void *info,const char *domain, Bc
static void _log_handler_destroy_cb(bctbx_log_handler_t *handler) {
LinphoneLoggingService *service = (LinphoneLoggingService *)bctbx_log_handler_get_user_data(handler);
bctbx_free(service->log_handler);
service->log_handler = NULL;
}
@ -158,11 +159,12 @@ LinphoneLoggingService *linphone_logging_service_ref(LinphoneLoggingService *ser
}
void linphone_logging_service_unref(LinphoneLoggingService *service) {
belle_sip_object_ref(service);
belle_sip_object_unref(service);
}
static void _linphone_logging_service_uninit(LinphoneLoggingService *log_service) {
if (log_service->log_handler) bctbx_remove_log_handler(log_service->log_handler);
if (log_service->log_handler)
bctbx_remove_log_handler(log_service->log_handler);
linphone_logging_service_cbs_unref(log_service->cbs);
}

View file

@ -476,7 +476,7 @@ const char * linphone_core_get_echo_canceller_filter_name(const LinphoneCore *lc
* task_fun must return BELLE_SIP_STOP when job is finished.
**/
void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description){
belle_sip_source_t *s=lc->sal->create_timer(task_fun,data, 20, task_description);
belle_sip_source_t *s=lc->sal->createTimer(task_fun,data, 20, task_description);
belle_sip_object_unref(s);
}

View file

@ -100,10 +100,11 @@ void linphone_player_close(LinphonePlayer *obj){
}
void linphone_player_destroy(LinphonePlayer *obj) {
if(obj->destroy) obj->destroy(obj);
_linphone_player_destroy(obj);
}
void _linphone_player_destroy(LinphonePlayer *player) {
if(player->destroy) player->destroy(player);
linphone_player_cbs_unref(player->callbacks);
}
@ -133,9 +134,13 @@ static bool_t call_player_check_state(LinphonePlayer *player, bool_t check_playe
static void on_eof(void *user_data, MSFilter *f, unsigned int event_id, void *arg){
LinphonePlayer *player=(LinphonePlayer *)user_data;
LinphonePlayerCbs *cbs = linphone_player_get_callbacks(player);
LinphonePlayerCbsEofReachedCb cb = linphone_player_cbs_get_eof_reached(cbs);
if (cb) cb(player);
switch (event_id){
case MS_PLAYER_EOF:
LinphonePlayerCbs *cbs = linphone_player_get_callbacks(player);
LinphonePlayerCbsEofReachedCb cb = linphone_player_cbs_get_eof_reached(cbs);
if (cb) cb(player);
break;
}
}
static int call_player_open(LinphonePlayer* player, const char *filename){

View file

@ -357,6 +357,7 @@ LinphoneStatus linphone_presence_model_set_contact(LinphonePresenceModel *model,
service = linphone_presence_service_new(NULL, LinphonePresenceBasicStatusClosed, NULL);
if (service == NULL) return -1;
linphone_presence_model_add_service(model, service);
linphone_presence_service_unref(service);
}
return linphone_presence_service_set_contact(service, contact);
}
@ -1562,7 +1563,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalSubscribeOp *op, const char
linphone_friend_add_incoming_subscription(lf, op);
lf->inc_subscribe_pending=TRUE;
if (lp_config_get_int(lc->config,"sip","notify_pending_state",0)) {
op->notify_pending_state();
op->notifyPendingState();
}
op->accept();
} else {
@ -1935,7 +1936,7 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, Sa
if (linphone_core_get_default_friend_list(lc) != NULL)
lf=linphone_core_find_friend_by_out_subscribe(lc, op);
if (lf==NULL && lp_config_get_int(lc->config,"sip","allow_out_of_subscribe_presence",0)){
char *buf = sal_address_as_string_uri_only(op->get_from_address());
char *buf = sal_address_as_string_uri_only(op->getFromAddress());
LinphoneAddress *addr = linphone_address_new(buf);
lf = linphone_core_find_friend(lc, addr);
ms_free(buf);
@ -1999,7 +2000,7 @@ void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){
linphone_friend_remove_incoming_subscription(lf, op);
}else{
/*case of an op that we already released because the friend was destroyed*/
ms_message("Receiving unsuscribe for unknown in-subscribtion from %s", op->get_from());
ms_message("Receiving unsuscribe for unknown in-subscribtion from %s", op->getFrom());
}
}

View file

@ -49,6 +49,8 @@ void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallSt
void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg);
void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received);
void linphone_call_notify_tmmbr_received(LinphoneCall *call, int stream_index, int tmmbr);
void linphone_call_notify_snapshot_taken(LinphoneCall *call, const char *file_path);
void linphone_call_notify_next_video_frame_decoded(LinphoneCall *call);
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg);
LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op);
@ -401,7 +403,7 @@ void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState stat
void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state);
void _linphone_event_notify_notify_response(const LinphoneEvent *lev);
LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss);
LinphoneContent *linphone_content_from_sal_body_handler(SalBodyHandler *ref);
LinphoneContent *linphone_content_from_sal_body_handler(const SalBodyHandler *ref);
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc);
void linphone_core_register_offer_answer_providers(LinphoneCore *lc);

View file

@ -436,7 +436,7 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *cfg, bool_t val){
}
void linphone_proxy_config_pause_register(LinphoneProxyConfig *cfg){
if (cfg->op) cfg->op->stop_refreshing();
if (cfg->op) cfg->op->stopRefreshing();
}
void linphone_proxy_config_edit(LinphoneProxyConfig *cfg){
@ -457,20 +457,16 @@ void linphone_proxy_config_apply(LinphoneProxyConfig *cfg,LinphoneCore *lc){
void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig * cfg){
LinphoneAddress *contact_addr = NULL;
{
const SalAddress *sal_addr = cfg->op && cfg->state == LinphoneRegistrationOk
? cfg->op->get_contact_address()
: NULL;
if (sal_addr) {
char *buf = sal_address_as_string(sal_addr);
contact_addr = buf ? linphone_address_new(buf) : NULL;
ms_free(buf);
}
const SalAddress *sal_addr = cfg->op && cfg->state == LinphoneRegistrationOk ? cfg->op->getContactAddress() : NULL;
if (sal_addr) {
char *buf = sal_address_as_string(sal_addr);
contact_addr = buf ? linphone_address_new(buf) : NULL;
ms_free(buf);
}
/*with udp, there is a risk of port reuse, so I prefer to not do anything for now*/
if (contact_addr) {
if (linphone_address_get_transport(contact_addr) != LinphoneTransportUdp) {
if (linphone_address_get_transport(contact_addr) != LinphoneTransportUdp && lp_config_get_int(cfg->lc->config, "sip", "unregister_previous_contact", 0)) {
if (cfg->pending_contact)
linphone_address_unref(cfg->pending_contact);
cfg->pending_contact=contact_addr;
@ -542,10 +538,10 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){
guess_contact_for_register(cfg);
if (cfg->contact_address)
cfg->op->set_contact_address(L_GET_PRIVATE_FROM_C_OBJECT(cfg->contact_address)->getInternalAddress());
cfg->op->set_user_pointer(cfg);
cfg->op->setContactAddress(L_GET_PRIVATE_FROM_C_OBJECT(cfg->contact_address)->getInternalAddress());
cfg->op->setUserPointer(cfg);
if (cfg->op->register_(
if (cfg->op->sendRegister(
proxy_string,
cfg->reg_identity,
cfg->expires,
@ -572,7 +568,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){
void linphone_proxy_config_refresh_register(LinphoneProxyConfig *cfg){
if (cfg->reg_sendregister && cfg->op && cfg->state!=LinphoneRegistrationProgress){
if (cfg->op->register_refresh(cfg->expires) == 0) {
if (cfg->op->refreshRegister(cfg->expires) == 0) {
linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress, "Refresh registration");
}
}
@ -854,7 +850,7 @@ LinphoneStatus linphone_proxy_config_done(LinphoneProxyConfig *cfg)
if (res == LinphoneProxyConfigAddressDifferent) {
_linphone_proxy_config_unregister(cfg);
}
cfg->op->set_user_pointer(NULL); /*we don't want to receive status for this un register*/
cfg->op->setUserPointer(NULL); /*we don't want to receive status for this un register*/
cfg->op->unref(); /*but we keep refresher to handle authentication if needed*/
cfg->op=NULL;
}
@ -1049,7 +1045,7 @@ struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig
const char *linphone_proxy_config_get_custom_header(LinphoneProxyConfig *cfg, const char *header_name){
const SalCustomHeader *ch;
if (!cfg->op) return NULL;
ch = cfg->op->get_recv_custom_header();
ch = cfg->op->getRecvCustomHeaders();
return sal_custom_header_find(ch, header_name);
}
@ -1420,7 +1416,7 @@ const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProx
}
const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) {
return cfg->op?(const LinphoneAddress*) cfg->op->get_service_route():NULL;
return cfg->op?(const LinphoneAddress*) cfg->op->getServiceRoute():NULL;
}
const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg) {
const char* addr=NULL;
@ -1500,7 +1496,7 @@ const LinphoneAddress *linphone_proxy_config_get_contact (const LinphoneProxyCon
// Warning : Do not remove, the op can change its contact_address
if (!cfg->op)
return NULL;
const SalAddress *salAddr = cfg->op->get_contact_address();
const SalAddress *salAddr = cfg->op->getContactAddress();
if (!salAddr)
return NULL;
if (cfg->contact_address)
@ -1542,7 +1538,7 @@ LinphoneNatPolicy * linphone_proxy_config_get_nat_policy(const LinphoneProxyConf
void linphone_proxy_config_set_nat_policy(LinphoneProxyConfig *cfg, LinphoneNatPolicy *policy) {
if (policy != NULL) {
policy = linphone_nat_policy_ref(policy); /* Prevent object destruction if the same policy is used */
linphone_nat_policy_ref(policy); /* Prevent object destruction if the same policy is used */
policy->lc = cfg->lc;
}
if (cfg->nat_policy != NULL) linphone_nat_policy_unref(cfg->nat_policy);
@ -1589,4 +1585,4 @@ bool_t linphone_proxy_config_is_push_notification_allowed(const LinphoneProxyCon
void linphone_proxy_config_set_push_notification_allowed(LinphoneProxyConfig *cfg, bool_t is_allowed) {
cfg->push_notification_allowed = is_allowed;
}
}

View file

@ -380,7 +380,7 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report,
sal_address_has_uri_param(salAddress, "maddr") ||
linphone_address_get_port(request_uri) != 0) {
ms_message("Publishing report with custom route %s", collector_uri);
lev->op->set_route(collector_uri);
lev->op->setRoute(collector_uri);
}
if (linphone_event_send_publish(lev, content) != 0){
@ -424,7 +424,7 @@ static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDesc
static void update_ip(LinphoneCall * call, int stats_type) {
SalStreamType sal_stream_type = stats_type == LINPHONE_CALL_STATS_AUDIO ? SalAudio : stats_type == LINPHONE_CALL_STATS_VIDEO ? SalVideo : SalText;
const SalStreamDescription * local_desc = get_media_stream_for_desc(_linphone_call_get_local_desc(call), sal_stream_type);
const SalStreamDescription * remote_desc = get_media_stream_for_desc(L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp()->get_remote_media_description(), sal_stream_type);
const SalStreamDescription * remote_desc = get_media_stream_for_desc(L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp()->getRemoteMediaDescription(), sal_stream_type);
LinphoneCallLog *log = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getLog();
if (local_desc != NULL) {
@ -444,7 +444,7 @@ static void update_ip(LinphoneCall * call, int stats_type) {
if (strlen(remote_desc->rtp_addr) > 0) {
STR_REASSIGN(log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr));
} else {
STR_REASSIGN(log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp()->get_remote_media_description()->addr));
STR_REASSIGN(log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp()->getRemoteMediaDescription()->addr));
}
}
}
@ -511,7 +511,7 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) {
if (!media_report_enabled(call, stats_type) || !L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp())
return;
dialog_id = L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp()->get_dialog_id();
dialog_id = L_GET_PRIVATE_FROM_C_OBJECT(call)->getOp()->getDialogId();
STR_REASSIGN(report->info.call_id, ms_strdup(log->call_id));

View file

@ -367,7 +367,7 @@ bool_t linphone_vcard_generate_unique_id(LinphoneVcard *vCard) {
if (linphone_vcard_get_uid(vCard)) {
return FALSE;
}
if (LinphonePrivate::Sal::generate_uuid(uuid, sizeof(uuid)) == 0) {
if (LinphonePrivate::Sal::generateUuid(uuid, sizeof(uuid)) == 0) {
char vcard_uuid[sizeof(uuid)+4];
snprintf(vcard_uuid, sizeof(vcard_uuid), "urn:%s", uuid);
linphone_vcard_set_uid(vCard, vcard_uuid);

View file

@ -88,6 +88,7 @@ static void cleanup_dead_vtable_refs(LinphoneCore *lc){
lc->vtable_notify_recursion--;
void linphone_core_notify_global_state_changed(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message) {
L_GET_PRIVATE_FROM_C_OBJECT(lc)->notifyGlobalStateChanged(gstate);
NOTIFY_IF_EXIST(global_state_changed,lc,gstate,message);
cleanup_dead_vtable_refs(lc);
}

View file

@ -79,6 +79,8 @@ set(DAEMON_SOURCE_FILES
commands/msfilter-add-fmtp.h
commands/netsim.cc
commands/netsim.h
commands/play.cc
commands/play.h
commands/play-wav.cc
commands/play-wav.h
commands/pop-event.cc

233
daemon/commands/play.cc Normal file
View file

@ -0,0 +1,233 @@
/*
play-wav.cc
Copyright (C) 2016 Belledonne Communications, Grenoble, France
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or (at
your option) any later version.
This library 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "play.h"
#include "call.h"
#include <utility>
using namespace std;
#define VOIDPTR_TO_INT(p) ((int)(intptr_t)(p))
void IncallPlayerStartCommand::onEof(LinphonePlayer *player){
pair<int, Daemon *> *callPlayingData = (pair<int, Daemon *> *)linphone_player_get_user_data(player);
Daemon *app = callPlayingData->second;
int id = callPlayingData->first;
app->callPlayingComplete(id);
delete callPlayingData;
linphone_player_set_user_data(player, NULL);
}
IncallPlayerStartCommand::IncallPlayerStartCommand() :
DaemonCommand("incall-player-start", "incall-player-start <filename> [<call_id>]",
"Play a WAV audio file or a MKV audio/video file. The played media stream will be sent through \n"
"the RTP session of the given call.\n"
"<filename> is the file to be played.\n") {
addExample(new DaemonCommandExample("incall-player-start /usr/local/share/sounds/linphone/hello8000.wav 1",
"Status: Ok\n"));
addExample(new DaemonCommandExample("incall-player-start /usr/local/share/sounds/linphone/hello8000.wav 1",
"Status: Error\n"
"Reason: No call with such id."));
addExample(new DaemonCommandExample("incall-player-start /usr/local/share/sounds/linphone/hello8000.wav",
"Status: Ok\n"));
addExample(new DaemonCommandExample("incall-player-start /usr/local/share/sounds/linphone/hello8000.wav",
"Status: Error\n"
"Reason: No active call."));
}
void IncallPlayerStartCommand::exec(Daemon *app, const string& args) {
LinphoneCall *call = NULL;
int cid;
const MSList *elem;
istringstream ist(args);
string filename;
ist >> filename;
if (ist.eof() && (filename.length() == 0)) {
app->sendResponse(Response("Missing filename parameter.", Response::Error));
return;
}
if (ist.fail()) {
app->sendResponse(Response("Incorrect filename parameter.", Response::Error));
return;
}
ist >> cid;
if (ist.fail()) {
elem = linphone_core_get_calls(app->getCore());
if (elem != NULL && elem->next == NULL) {
call = (LinphoneCall*)elem->data;
}
} else {
call = app->findCall(cid);
if (call == NULL) {
app->sendResponse(Response("No call with such id."));
return;
}
}
if (call == NULL) {
app->sendResponse(Response("No active call."));
return;
}
LinphonePlayer *p = linphone_call_get_player(call);
LinphonePlayerCbs *cbs=linphone_player_get_callbacks(p);
pair<int, Daemon *> *callPlayingData = (pair<int, Daemon *> *)linphone_player_get_user_data(p);
if(callPlayingData) callPlayingData = new pair<int, Daemon *>({
VOIDPTR_TO_INT(linphone_call_get_user_data(call)),
app
});
linphone_player_set_user_data(p, callPlayingData);
linphone_player_cbs_set_eof_reached(cbs, onEof);
linphone_player_open(p,filename.c_str());
linphone_player_start(p);
app->sendResponse(Response());
}
IncallPlayerStopCommand::IncallPlayerStopCommand() :
DaemonCommand("incall-player-stop", "incall-player-stop [<call_id>]","Close the opened file.\n") {
addExample(new DaemonCommandExample("incall-player-stop 1",
"Status: Error\n"
"Reason: No call with such id."));
addExample(new DaemonCommandExample("incall-player-stop 1",
"Status: Ok\n"));
addExample(new DaemonCommandExample("incall-player-stop",
"Status: Ok\n"));
addExample(new DaemonCommandExample("incall-player-stop",
"Status: Error\n"
"Reason: No active call."));
}
void IncallPlayerStopCommand::exec(Daemon *app, const string& args) {
LinphoneCall *call = NULL;
int cid;
const MSList *elem;
istringstream ist(args);
ist >> cid;
if (ist.fail()) {
elem = linphone_core_get_calls(app->getCore());
if (elem != NULL && elem->next == NULL) {
call = (LinphoneCall*)elem->data;
}
} else {
call = app->findCall(cid);
if (call == NULL) {
app->sendResponse(Response("No call with such id."));
return;
}
}
if (call == NULL) {
app->sendResponse(Response("No active call."));
return;
}
LinphonePlayer *p = linphone_call_get_player(call);
linphone_player_close(p);
app->sendResponse(Response());
pair<int, Daemon *> *callPlayingData = (pair<int, Daemon *> *)linphone_player_get_user_data(p);
if(callPlayingData) delete callPlayingData;
}
IncallPlayerPauseCommand::IncallPlayerPauseCommand() :
DaemonCommand("incall-player-pause", "incall-player-pause [<call_id>]",
"Pause the playing of a file.\n") {
addExample(new DaemonCommandExample("incall-player-pause 1",
"Status: Error\n"
"Reason: No call with such id."));
addExample(new DaemonCommandExample("incall-player-pause 1",
"Status: Ok\n"));
addExample(new DaemonCommandExample("incall-player-pause",
"Status: Ok\n"));
addExample(new DaemonCommandExample("incall-player-pause",
"Status: Error\n"
"Reason: No active call."));
}
void IncallPlayerPauseCommand::exec(Daemon *app, const string& args) {
LinphoneCall *call = NULL;
int cid;
const MSList *elem;
istringstream ist(args);
ist >> cid;
if (ist.fail()) {
elem = linphone_core_get_calls(app->getCore());
if (elem != NULL && elem->next == NULL) {
call = (LinphoneCall*)elem->data;
}
} else {
call = app->findCall(cid);
if (call == NULL) {
app->sendResponse(Response("No call with such id."));
return;
}
}
if (call == NULL) {
app->sendResponse(Response("No active call."));
return;
}
LinphonePlayer *p = linphone_call_get_player(call);
linphone_player_pause(p);
app->sendResponse(Response());
}
IncallPlayerResumeCommand::IncallPlayerResumeCommand() :
DaemonCommand("incall-player-resume", "incall-player-resume [<call_id>]",
"Unpause the playing of a file.\n") {
addExample(new DaemonCommandExample("incall-player-resume 1",
"Status: Error\n"
"Reason: No call with such id."));
addExample(new DaemonCommandExample("incall-player-resume 1",
"Status: Ok\n"));
addExample(new DaemonCommandExample("incall-player-resume",
"Status: Ok\n"));
addExample(new DaemonCommandExample("incall-player-resume",
"Status: Error\n"
"Reason: No active call."));
}
void IncallPlayerResumeCommand::exec(Daemon *app, const string& args) {
LinphoneCall *call = NULL;
int cid;
const MSList *elem;
istringstream ist(args);
ist >> cid;
if (ist.fail()) {
elem = linphone_core_get_calls(app->getCore());
if (elem != NULL && elem->next == NULL) {
call = (LinphoneCall*)elem->data;
}
} else {
call = app->findCall(cid);
if (call == NULL) {
app->sendResponse(Response("No call with such id."));
return;
}
}
if (call == NULL) {
app->sendResponse(Response("No active call."));
return;
}
LinphonePlayer *p = linphone_call_get_player(call);
linphone_player_start(p);
app->sendResponse(Response());
}

55
daemon/commands/play.h Normal file
View file

@ -0,0 +1,55 @@
/*
play-wav.h
Copyright (C) 2016 Belledonne Communications, Grenoble, France
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or (at
your option) any later version.
This library 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LINPHONE_DAEMON_COMMAND_PLAY_H_
#define LINPHONE_DAEMON_COMMAND_PLAY_H_
#include "daemon.h"
class IncallPlayerStartCommand: public DaemonCommand {
public:
IncallPlayerStartCommand();
void exec (Daemon *app, const std::string& args) override;
private:
static void onEof(LinphonePlayer *player);
};
class IncallPlayerStopCommand: public DaemonCommand {
public:
IncallPlayerStopCommand();
void exec (Daemon *app, const std::string& args) override;
};
class IncallPlayerPauseCommand: public DaemonCommand {
public:
IncallPlayerPauseCommand();
void exec (Daemon *app, const std::string& args) override;
};
class IncallPlayerResumeCommand: public DaemonCommand {
public:
IncallPlayerResumeCommand();
void exec (Daemon *app, const std::string& args) override;
};
#endif // LINPHONE_DAEMON_COMMAND_PLAY_H_

View file

@ -79,6 +79,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "commands/netsim.h"
#include "commands/cn.h"
#include "commands/version.h"
#include "commands/play.h"
#include "private.h"
using namespace std;
@ -121,13 +122,18 @@ void *Daemon::iterateThread(void *arg) {
}
EventResponse::EventResponse(Daemon *daemon, LinphoneCall *call, LinphoneCallState state) {
LinphoneCallLog *callLog = linphone_call_get_call_log(call);
const LinphoneAddress *fromAddr = linphone_call_log_get_from_address(callLog);
char *fromStr = linphone_address_as_string(fromAddr);
ostringstream ostr;
char *remote = linphone_call_get_remote_address_as_string(call);
ostr << "Event-type: call-state-changed\nEvent: " << linphone_call_state_to_string(state) << "\n";
ostr << "From: " << remote << "\n";
ostr << "Event-type: call-state-changed" << "\n";
ostr << "Event: " << linphone_call_state_to_string(state) << "\n";
ostr << "From: " << fromStr << "\n";
ostr << "Id: " << daemon->updateCallId(call) << "\n";
setBody(ostr.str().c_str());
ms_free(remote);
bctbx_free(fromStr);
}
DtmfResponse::DtmfResponse(Daemon *daemon, LinphoneCall *call, int dtmf) {
@ -214,6 +220,15 @@ AudioStreamStatsResponse::AudioStreamStatsResponse(Daemon* daemon, AudioStream*
setBody(ostr.str().c_str());
}
CallPlayingStatsResponse::CallPlayingStatsResponse(Daemon* daemon, int id) {
ostringstream ostr;
ostr << "Event-type: call-playing-complete\n";
ostr << "Id: " << id << "\n";
setBody(ostr.str().c_str());
}
PayloadTypeResponse::PayloadTypeResponse(LinphoneCore *core, const PayloadType *payloadType, int index, const string &prefix, bool enabled_status) {
ostringstream ostr;
if (payloadType != NULL) {
@ -486,6 +501,10 @@ void Daemon::initCommands() {
mCommands.push_back(new ConfigSetCommand());
mCommands.push_back(new NetsimCommand());
mCommands.push_back(new CNCommand());
mCommands.push_back(new IncallPlayerStartCommand());
mCommands.push_back(new IncallPlayerStopCommand());
mCommands.push_back(new IncallPlayerPauseCommand());
mCommands.push_back(new IncallPlayerResumeCommand());
mCommands.sort(compareCommands);
}
@ -524,6 +543,10 @@ void Daemon::callStatsUpdated(LinphoneCall *call, const LinphoneCallStats *stats
}
}
void Daemon::callPlayingComplete(int id) {
mEventQueue.push(new CallPlayingStatsResponse(this, id));
}
void Daemon::dtmfReceived(LinphoneCall *call, int dtmf) {
mEventQueue.push(new DtmfResponse(this, call, dtmf));
}

View file

@ -160,6 +160,11 @@ public:
const LinphoneCallStats *stats, bool event);
};
class CallPlayingStatsResponse: public Response {
public:
CallPlayingStatsResponse(Daemon *daemon, int id);
};
class DtmfResponse: public Response {
public:
DtmfResponse(Daemon *daemon, LinphoneCall *call, int dtmf);
@ -230,7 +235,7 @@ public:
void dumpCommandsHelpHtml();
void enableStatsEvents(bool enabled);
void enableLSD(bool enabled);
void callPlayingComplete(int id);
void setAutoVideo( bool enabled ){ mAutoVideo = enabled; }
inline bool autoVideo(){ return mAutoVideo; }

View file

@ -188,8 +188,8 @@ LINPHONE_PUBLIC bool_t linphone_address_weak_equal (const LinphoneAddress *addre
LINPHONE_PUBLIC bool_t linphone_address_equal (const LinphoneAddress *address1, const LinphoneAddress *address2);
/**
* Get the header encoded in the address.
* @param address the address
* Get the header encoded in the address.
* @param header_name the header name
**/
LINPHONE_PUBLIC const char *linphone_address_get_header (const LinphoneAddress *address, const char *header_name);

View file

@ -173,6 +173,34 @@ LINPHONE_PUBLIC LinphoneCallCbsTmmbrReceivedCb linphone_call_cbs_get_tmmbr_recei
*/
LINPHONE_PUBLIC void linphone_call_cbs_set_tmmbr_received(LinphoneCallCbs *cbs, LinphoneCallCbsTmmbrReceivedCb cb);
/**
* Get the snapshot taken callback.
* @param[in] cbs LinphoneCallCbs object.
* @return The current snapshot taken callback.
*/
LINPHONE_PUBLIC LinphoneCallCbsSnapshotTakenCb linphone_call_cbs_get_snapshot_taken(LinphoneCallCbs *cbs);
/**
* Set the snapshot taken callback.
* @param[in] cbs LinphoneCallCbs object.
* @param[in] cb The snapshot taken callback to be used.
*/
LINPHONE_PUBLIC void linphone_call_cbs_set_snapshot_taken(LinphoneCallCbs *cbs, LinphoneCallCbsSnapshotTakenCb cb);
/**
* Get the next video frame decoded callback.
* @param[in] cbs LinphoneCallCbs object.
* @return The current next video frame decoded callback.
*/
LINPHONE_PUBLIC LinphoneCallCbsNextVideoFrameDecodedCb linphone_call_cbs_get_next_video_frame_decoded(LinphoneCallCbs *cbs);
/**
* Set the next video frame decoded callback.
* @param[in] cbs LinphoneCallCbs object.
* @param[in] cb The next video frame decoded callback to be used.
*/
LINPHONE_PUBLIC void linphone_call_cbs_set_next_video_frame_decoded(LinphoneCallCbs *cbs, LinphoneCallCbsNextVideoFrameDecodedCb cb);
/**
* @}
*/

View file

@ -95,6 +95,19 @@ typedef void (*LinphoneCallCbsAckProcessingCb)(LinphoneCall *call, LinphoneHeade
*/
typedef void (*LinphoneCallCbsTmmbrReceivedCb)(LinphoneCall *call, int stream_index, int tmmbr);
/**
* Callback for notifying a snapshot taken.
* @param call LinphoneCall for which the snapshot was taken
* @param filepath the name of the saved file
*/
typedef void (*LinphoneCallCbsSnapshotTakenCb)(LinphoneCall *call, const char *filepath);
/**
* Callback to notify a next video frame has been decoded
* @param call LinphoneCall for which the next video frame has been decoded
*/
typedef void (*LinphoneCallCbsNextVideoFrameDecodedCb)(LinphoneCall *call);
/**
* @}
**/

View file

@ -20,12 +20,12 @@
#ifndef _L_C_CHAT_MESSAGE_H_
#define _L_C_CHAT_MESSAGE_H_
#include "linphone/api/c-types.h"
#include "linphone/api/c-chat-message-cbs.h"
#include "linphone/api/c-types.h"
#ifdef SQLITE_STORAGE_ENABLED
#include <sqlite3.h>
#endif
#include <sqlite3.h>
#endif // ifdef SQLITE_STORAGE_ENABLED
// =============================================================================
@ -37,7 +37,7 @@ typedef enum _LinphoneChatMessageDir{
// =============================================================================
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif // ifdef __cplusplus
/**
@ -47,99 +47,101 @@ typedef enum _LinphoneChatMessageDir{
/**
* Acquire a reference to the chat message.
* @param[in] cr The chat message.
* @param[in] msg #LinphoneChatMessage object.
* @return The same chat message.
**/
LINPHONE_PUBLIC LinphoneChatMessage *linphone_chat_message_ref(LinphoneChatMessage *msg);
*/
LINPHONE_PUBLIC LinphoneChatMessage *linphone_chat_message_ref (LinphoneChatMessage *msg);
/**
* Release reference to the chat message.
* @param[in] cr The chat message.
**/
LINPHONE_PUBLIC void linphone_chat_message_unref(LinphoneChatMessage *msg);
* @param[in] msg #LinphoneChatMessage object.
*/
LINPHONE_PUBLIC void linphone_chat_message_unref (LinphoneChatMessage *msg);
/**
* Retrieve the user pointer associated with the chat message.
* @param[in] cr The chat message.
* @param[in] msg #LinphoneChatMessage object.
* @return The user pointer associated with the chat message.
**/
LINPHONE_PUBLIC void *linphone_chat_message_get_user_data(const LinphoneChatMessage *msg);
*/
LINPHONE_PUBLIC void *linphone_chat_message_get_user_data (const LinphoneChatMessage *msg);
/**
* Assign a user pointer to the chat message.
* @param[in] cr The chat message.
* @param[in] msg #LinphoneChatMessage object.
* @param[in] ud The user pointer to associate with the chat message.
**/
LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage *msg, void *ud);
*/
LINPHONE_PUBLIC void linphone_chat_message_set_user_data (LinphoneChatMessage *msg, void *ud);
// =============================================================================
LINPHONE_PUBLIC const char * linphone_chat_message_get_external_body_url(const LinphoneChatMessage *msg);
LINPHONE_PUBLIC const char *linphone_chat_message_get_external_body_url (const LinphoneChatMessage *msg);
LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage *msg, const char *external_body_url);
LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url (LinphoneChatMessage *msg, const char *external_body_url);
/**
* Get the time the message was sent.
* @param[in] msg #LinphoneChatMessage object.
*/
LINPHONE_PUBLIC time_t linphone_chat_message_get_time(const LinphoneChatMessage* msg);
LINPHONE_PUBLIC time_t linphone_chat_message_get_time (const LinphoneChatMessage *msg);
/**
* Returns TRUE if the message has been sent, returns FALSE if the message has been received.
* @param message the message
**/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* msg);
* @param[in] msg #LinphoneChatMessage object.
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing (LinphoneChatMessage *msg);
/**
* Get origin of the message
* @param[in] message #LinphoneChatMessage obj
* @param[in] msg #LinphoneChatMessage object.
* @return #LinphoneAddress
*/
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from_address(LinphoneChatMessage* msg);
LINPHONE_PUBLIC const LinphoneAddress *linphone_chat_message_get_from_address (LinphoneChatMessage *msg);
/**
* Get destination of the message
* @param[in] message #LinphoneChatMessage obj
* @param[in] msg #LinphoneChatMessage object.
* @return #LinphoneAddress
*/
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to_address(LinphoneChatMessage* msg);
LINPHONE_PUBLIC const LinphoneAddress *linphone_chat_message_get_to_address (LinphoneChatMessage *msg);
/**
* Get the content type of a chat message.
* @param[in] message #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @return The content type of the chat message
*/
LINPHONE_PUBLIC const char * linphone_chat_message_get_content_type(LinphoneChatMessage *msg);
LINPHONE_PUBLIC const char *linphone_chat_message_get_content_type (LinphoneChatMessage *msg);
/**
* Set the content type of a chat message.
* This content type must match a content that is text representable, such as text/plain, text/html or image/svg+xml.
* @param[in] message #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @param[in] content_type The new content type of the chat message
*/
LINPHONE_PUBLIC void linphone_chat_message_set_content_type(LinphoneChatMessage *msg, const char *content_type);
LINPHONE_PUBLIC void linphone_chat_message_set_content_type (LinphoneChatMessage *msg, const char *content_type);
/**
* Get text part of this message
* @param[in] msg #LinphoneChatMessage object.
* @return text or NULL if no text.
* @deprecated use getTextContent() instead
*/
LINPHONE_PUBLIC const char* linphone_chat_message_get_text(LinphoneChatMessage* msg);
LINPHONE_PUBLIC const char *linphone_chat_message_get_text (LinphoneChatMessage* msg);
/**
* Get the message identifier.
* It is used to identify a message so that it can be notified as delivered and/or displayed.
* @param[in] cm #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @return The message identifier.
*/
LINPHONE_PUBLIC const char* linphone_chat_message_get_message_id(const LinphoneChatMessage *msg);
LINPHONE_PUBLIC const char *linphone_chat_message_get_message_id (const LinphoneChatMessage *msg);
/**
* Linphone message has an app-specific field that can store a text. The application might want
* to use it for keeping data over restarts, like thumbnail image path.
* @param message #LinphoneChatMessage
* @param[in] msg #LinphoneChatMessage object.
* @return the application-specific data or NULL if none has been stored.
*/
LINPHONE_PUBLIC const char* linphone_chat_message_get_appdata(const LinphoneChatMessage* message);
LINPHONE_PUBLIC const char *linphone_chat_message_get_appdata (const LinphoneChatMessage *msg);
/**
* Linphone message has an app-specific field that can store a text. The application might want
@ -148,247 +150,244 @@ LINPHONE_PUBLIC const char* linphone_chat_message_get_appdata(const LinphoneChat
* Invoking this function will attempt to update the message storage to reflect the changeif it is
* enabled.
*
* @param message #LinphoneChatMessage
* @param[in] msg #LinphoneChatMessage object.
* @param data the data to store into the message
*/
LINPHONE_PUBLIC void linphone_chat_message_set_appdata(LinphoneChatMessage* message, const char* data);
LINPHONE_PUBLIC void linphone_chat_message_set_appdata (LinphoneChatMessage *msg, const char *data);
/**
* Returns the chatroom this message belongs to.
**/
LINPHONE_PUBLIC LinphoneChatRoom* linphone_chat_message_get_chat_room(const LinphoneChatMessage *msg);
* @param[in] msg #LinphoneChatMessage object.
*/
LINPHONE_PUBLIC LinphoneChatRoom *linphone_chat_message_get_chat_room (const LinphoneChatMessage *msg);
/**
* Get the path to the file to read from or write to during the file transfer.
* @param[in] msg #LinphoneChatMessage object
* @return The path to the file to use for the file transfer.
*/
LINPHONE_PUBLIC const char * linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg);
LINPHONE_PUBLIC const char *linphone_chat_message_get_file_transfer_filepath (LinphoneChatMessage *msg);
// =============================================================================
/**
* Get if a chat message is to be stored.
* @param[in] message #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @return Whether or not the message is to be stored
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_get_to_be_stored(const LinphoneChatMessage *message);
LINPHONE_PUBLIC bool_t linphone_chat_message_get_to_be_stored (const LinphoneChatMessage *msg);
/**
* Set if a chat message is to be stored.
* This content type must match a content that is text representable, such as text/plain, text/html or image/svg+xml.
* @param[in] message #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @param[in] to_be_stored Whether or not the chat message is to be stored
*/
LINPHONE_PUBLIC void linphone_chat_message_set_to_be_stored(LinphoneChatMessage *message, bool_t to_be_stored);
LINPHONE_PUBLIC void linphone_chat_message_set_to_be_stored (LinphoneChatMessage *msg, bool_t to_be_stored);
LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *msg);
LINPHONE_PUBLIC unsigned int linphone_chat_message_store (LinphoneChatMessage *msg);
/**
* Get the state of the message
*@param message #LinphoneChatMessage obj
*@return #LinphoneChatMessageState
* @param[in] msg #LinphoneChatMessage object.
* @return #LinphoneChatMessageState
*/
LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message);
LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state (const LinphoneChatMessage *msg);
/**
* Get if the message was encrypted when transfered
* @param[in] message #LinphoneChatMessage obj
* @param[in] msg #LinphoneChatMessage object.
* @return whether the message was encrypted when transfered or not
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_secured(LinphoneChatMessage *msg);
LINPHONE_PUBLIC bool_t linphone_chat_message_is_secured (LinphoneChatMessage *msg);
/**
* Linphone message can carry external body as defined by rfc2017
* @param message #LinphoneChatMessage
* @param[in] msg #LinphoneChatMessage object.
* @return external body url or NULL if not present.
*/
LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message);
LINPHONE_PUBLIC const char *linphone_chat_message_get_external_body_url (const LinphoneChatMessage *msg);
/**
* Linphone message can carry external body as defined by rfc2017
*
* @param message a #LinphoneChatMessage
* @param[in] msg #LinphoneChatMessage object.
* @param url ex: access-type=URL; URL="http://www.foo.com/file"
*/
LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url);
LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url (LinphoneChatMessage *msg,const char *url);
/**
* Get the file_transfer_information (used by call backs to recover informations during a rcs file transfer)
*
* @param message #LinphoneChatMessage
* @param[in] msg #LinphoneChatMessage object.
* @return a pointer to the #LinphoneContent structure or NULL if not present.
*/
LINPHONE_PUBLIC LinphoneContent* linphone_chat_message_get_file_transfer_information(LinphoneChatMessage* message);
LINPHONE_PUBLIC LinphoneContent *linphone_chat_message_get_file_transfer_information (LinphoneChatMessage *msg);
/**
* Return whether or not a chat message is a file tranfer.
* @param[in] message #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object
* @return Whether or not the message is a file tranfer
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer(LinphoneChatMessage *message);
LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer (LinphoneChatMessage *msg);
/**
* Return whether or not a chat message is a text.
* @param[in] message #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @return Whether or not the message is a text
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_text(LinphoneChatMessage *message);
LINPHONE_PUBLIC bool_t linphone_chat_message_is_text (LinphoneChatMessage *msg);
/**
* Start the download of the file from remote server
*
* @param message #LinphoneChatMessage
* @param[in] msg #LinphoneChatMessage object.
* @param status_cb #LinphoneChatMessageStateChangeCb status callback invoked when file is downloaded or could not be downloaded
* @param ud user data
* @deprecated Use linphone_chat_message_download_file() instead.
* @donotwrap
*/
LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_message_start_file_download(LinphoneChatMessage* message, LinphoneChatMessageStateChangedCb status_cb, void* ud);
LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_message_start_file_download (
LinphoneChatMessage *msg,
LinphoneChatMessageStateChangedCb status_cb,
void *ud
);
/**
* Start the download of the file referenced in a #LinphoneChatMessage from remote server.
* @param[in] message #LinphoneChatMessage object.
* @param[in] msg #LinphoneChatMessage object.
*/
LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *message);
LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_download_file (LinphoneChatMessage *msg);
/**
* Cancel an ongoing file transfer attached to this message.(upload or download)
* @param msg #LinphoneChatMessage
* @param[in] msg #LinphoneChatMessage object.
*/
LINPHONE_PUBLIC void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage* msg);
LINPHONE_PUBLIC void linphone_chat_message_cancel_file_transfer (LinphoneChatMessage *msg);
/**
* Send a chat message.
* @param[in] msg #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
*/
LINPHONE_PUBLIC void linphone_chat_message_send (LinphoneChatMessage *msg);
/**
* Resend a chat message if it is in the 'not delivered' state for whatever reason.
* @param[in] msg #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @deprecated Use linphone_chat_message_send instead.
* @donotwrap
*/
LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_message_resend(LinphoneChatMessage *msg);
LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_chat_message_resend (LinphoneChatMessage *msg);
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg);
LINPHONE_PUBLIC const LinphoneAddress *linphone_chat_message_get_peer_address (LinphoneChatMessage *msg);
/**
* Returns the origin address of a message if it was a outgoing message, or the destination address if it was an incoming message.
*@param message #LinphoneChatMessage obj
*@return #LinphoneAddress
* @param[in] msg #LinphoneChatMessage object.
* @return #LinphoneAddress
*/
LINPHONE_PUBLIC const LinphoneAddress *linphone_chat_message_get_local_address(LinphoneChatMessage* message);
LINPHONE_PUBLIC const LinphoneAddress *linphone_chat_message_get_local_address (LinphoneChatMessage *msg);
/**
* Add custom headers to the message.
* @param message the message
* @param[in] msg #LinphoneChatMessage object.
* @param header_name name of the header
* @param header_value header value
**/
LINPHONE_PUBLIC void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value);
*/
LINPHONE_PUBLIC void linphone_chat_message_add_custom_header (
LinphoneChatMessage *msg,
const char *header_name,
const char *header_value
);
/**
* Retrieve a custom header value given its name.
* @param message the message
* @param[in] msg #LinphoneChatMessage object.
* @param header_name header name searched
**/
LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name);
*/
LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header (LinphoneChatMessage *msg, const char *header_name);
/**
* Removes a custom header from the message.
* @param msg the message
* @param[in] msg #LinphoneChatMessage object.
* @param header_name name of the header to remove
**/
LINPHONE_PUBLIC void linphone_chat_message_remove_custom_header(LinphoneChatMessage *msg, const char *header_name);
*/
LINPHONE_PUBLIC void linphone_chat_message_remove_custom_header (LinphoneChatMessage *msg, const char *header_name);
/**
* Returns TRUE if the message has been read, otherwise returns FALSE.
* @param message the message
**/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_read(LinphoneChatMessage* message);
* @param[in] msg #LinphoneChatMessage object.
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_read (LinphoneChatMessage *msg);
LINPHONE_PUBLIC LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg);
LINPHONE_PUBLIC LinphoneReason linphone_chat_message_get_reason (LinphoneChatMessage *msg);
/**
* Get full details about delivery error of a chat message.
* @param msg a #LinphoneChatMessage
* @param[in] msg #LinphoneChatMessage object.
* @return a #LinphoneErrorInfo describing the details.
**/
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg);
*/
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_chat_message_get_error_info (const LinphoneChatMessage *msg);
/**
* Set the path to the file to read from or write to during the file transfer.
* @param[in] msg #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @param[in] filepath The path to the file to use for the file transfer.
*/
LINPHONE_PUBLIC void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath);
LINPHONE_PUBLIC void linphone_chat_message_set_file_transfer_filepath (LinphoneChatMessage *msg, const char *filepath);
/**
* Fulfill a chat message char by char. Message linked to a Real Time Text Call send char in realtime following RFC 4103/T.140
* To commit a message, use #linphone_chat_room_send_message
* @param[in] msg #LinphoneChatMessage
* @param[in] msg #LinphoneChatMessage object.
* @param[in] character T.140 char
* @returns 0 if succeed.
*/
LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_put_char(LinphoneChatMessage *msg,uint32_t character);
LINPHONE_PUBLIC LinphoneStatus linphone_chat_message_put_char (LinphoneChatMessage *msg, uint32_t character);
/**
* Get the #LinphoneChatMessageCbs object associated with the LinphoneChatMessage.
* @param[in] msg #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @return The #LinphoneChatMessageCbs object associated with the LinphoneChatMessage.
*/
LINPHONE_PUBLIC LinphoneChatMessageCbs * linphone_chat_message_get_callbacks(const LinphoneChatMessage *msg);
LINPHONE_PUBLIC LinphoneChatMessageCbs *linphone_chat_message_get_callbacks (const LinphoneChatMessage *msg);
/**
* Adds a content to the ChatMessage
* @param[in] msg #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @param[in] c_content #LinphoneContent object
*/
LINPHONE_PUBLIC void linphone_chat_message_add_text_content(LinphoneChatMessage *msg, const char *c_content);
LINPHONE_PUBLIC void linphone_chat_message_add_text_content (LinphoneChatMessage *msg, const char *c_content);
/**
* Returns true if the chat message has a text content
* @param[in] msg #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @return true if it has one, false otherwise
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_has_text_content(const LinphoneChatMessage *msg);
LINPHONE_PUBLIC bool_t linphone_chat_message_has_text_content (const LinphoneChatMessage *msg);
/**
* Gets the text content if available as a string
* @param[in] msg #LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @return the #LinphoneContent buffer if available, null otherwise
*/
LINPHONE_PUBLIC const char* linphone_chat_message_get_text_content(const LinphoneChatMessage *msg);
LINPHONE_PUBLIC const char *linphone_chat_message_get_text_content (const LinphoneChatMessage *msg);
/**
* Gets whether or not a file is currently being downloaded or uploaded
* @param[in] msg LinphoneChatMessage object
* @param[in] msg #LinphoneChatMessage object.
* @return true if download or upload is in progress, false otherwise
*/
LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer_in_progress(LinphoneChatMessage *msg);
LINPHONE_PUBLIC bool_t linphone_chat_message_is_file_transfer_in_progress (LinphoneChatMessage *msg);
/**
* Gets the list of participants that displayed this message and the time at which they did.
* @param[in] msg LinphoneChatMessage object
* Gets the list of participants for which the imdn state has reached the specified state and the time at which they did.
* @param[in] msg #LinphoneChatMessage object.
* @param[in] state The LinphoneChatMessageState the imdn have reached (only use LinphoneChatMessageStateDelivered,
* LinphoneChatMessageStateDeliveredToUser, LinphoneChatMessageStateDisplayed and LinphoneChatMessageStateNotDelivered)
* @return \bctbx_list{LinphoneParticipantImdnState}
*/
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_that_have_displayed (const LinphoneChatMessage *msg);
/**
* Gets the list of participants that did not receive this message.
* @param[in] msg LinphoneChatMessage object
* @return \bctbx_list{LinphoneParticipantImdnState}
*/
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_that_have_not_received (const LinphoneChatMessage *msg);
/**
* Gets the list of participants that received this message and the time at which they did.
* @param[in] msg LinphoneChatMessage object
* @return \bctbx_list{LinphoneParticipantImdnState}
*/
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_that_have_received (const LinphoneChatMessage *msg);
LINPHONE_PUBLIC bctbx_list_t *linphone_chat_message_get_participants_by_imdn_state (const LinphoneChatMessage *msg, LinphoneChatMessageState state);
/**
* @}

View file

@ -38,55 +38,55 @@
* @param[in] content #LinphoneContent object.
* @return The same #LinphoneContent object.
**/
LINPHONE_PUBLIC LinphoneContent * linphone_content_ref(LinphoneContent *content);
LINPHONE_PUBLIC LinphoneContent *linphone_content_ref (LinphoneContent *content);
/**
* Release reference to the content.
* @param[in] content #LinphoneContent object.
**/
LINPHONE_PUBLIC void linphone_content_unref(LinphoneContent *content);
LINPHONE_PUBLIC void linphone_content_unref (LinphoneContent *content);
/**
* Retrieve the user pointer associated with the content.
* @param[in] content #LinphoneContent object.
* @return The user pointer associated with the content.
**/
LINPHONE_PUBLIC void *linphone_content_get_user_data(const LinphoneContent *content);
LINPHONE_PUBLIC void *linphone_content_get_user_data (const LinphoneContent *content);
/**
* Assign a user pointer to the content.
* @param[in] content #LinphoneContent object.
* @param[in] ud The user pointer to associate with the content.
**/
LINPHONE_PUBLIC void linphone_content_set_user_data(LinphoneContent *content, void *ud);
LINPHONE_PUBLIC void linphone_content_set_user_data (LinphoneContent *content, void *user_data);
/**
* Get the mime type of the content data.
* @param[in] content #LinphoneContent object.
* @return The mime type of the content data, for example "application".
*/
LINPHONE_PUBLIC const char * linphone_content_get_type(const LinphoneContent *content);
LINPHONE_PUBLIC const char *linphone_content_get_type (const LinphoneContent *content);
/**
* Set the mime type of the content data.
* @param[in] content #LinphoneContent object.
* @param[in] type The mime type of the content data, for example "application".
*/
LINPHONE_PUBLIC void linphone_content_set_type(LinphoneContent *content, const char *type);
LINPHONE_PUBLIC void linphone_content_set_type (LinphoneContent *content, const char *type);
/**
* Get the mime subtype of the content data.
* @param[in] content #LinphoneContent object.
* @return The mime subtype of the content data, for example "html".
*/
LINPHONE_PUBLIC const char * linphone_content_get_subtype(const LinphoneContent *content);
LINPHONE_PUBLIC const char *linphone_content_get_subtype (const LinphoneContent *content);
/**
* Set the mime subtype of the content data.
* @param[in] content #LinphoneContent object.
* @param[in] subtype The mime subtype of the content data, for example "html".
*/
LINPHONE_PUBLIC void linphone_content_set_subtype(LinphoneContent *content, const char *subtype);
LINPHONE_PUBLIC void linphone_content_set_subtype (LinphoneContent *content, const char *subtype);
/**
* Adds a parameter to the ContentType header.
@ -94,14 +94,18 @@ LINPHONE_PUBLIC void linphone_content_set_subtype(LinphoneContent *content, cons
* @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);
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.
* @return The content data buffer.
*/
LINPHONE_PUBLIC uint8_t * linphone_content_get_buffer(const LinphoneContent *content);
LINPHONE_PUBLIC const uint8_t *linphone_content_get_buffer (const LinphoneContent *content);
/**
* Set the content data buffer, usually a string.
@ -109,70 +113,77 @@ LINPHONE_PUBLIC uint8_t * linphone_content_get_buffer(const LinphoneContent *con
* @param[in] buffer The content data buffer.
* @param[in] size The size of the content data buffer.
*/
LINPHONE_PUBLIC void linphone_content_set_buffer(LinphoneContent *content, const uint8_t *buffer, size_t size);
LINPHONE_PUBLIC void linphone_content_set_buffer (LinphoneContent *content, const uint8_t *buffer, size_t size);
/**
* Get the string content data buffer.
* @param[in] content #LinphoneContent object
* @return The string content data buffer.
*/
LINPHONE_PUBLIC const char * linphone_content_get_string_buffer(const LinphoneContent *content);
LINPHONE_PUBLIC const char *linphone_content_get_string_buffer (const LinphoneContent *content);
/**
* Set the string content data buffer.
* @param[in] content #LinphoneContent object.
* @param[in] buffer The string content data buffer.
*/
LINPHONE_PUBLIC void linphone_content_set_string_buffer(LinphoneContent *content, const char *buffer);
LINPHONE_PUBLIC void linphone_content_set_string_buffer (LinphoneContent *content, const char *buffer);
/**
* Get the content data buffer size, excluding null character despite null character is always set for convenience.
* @param[in] content #LinphoneContent object.
* @return The content data buffer size.
*/
LINPHONE_PUBLIC size_t linphone_content_get_size(const LinphoneContent *content);
LINPHONE_PUBLIC size_t linphone_content_get_size (const LinphoneContent *content);
/**
* Get the file size if content is either a FileContent or a FileTransferContent.
* @param[in] content #LinphoneContent object.
* @return The represented file size.
*/
LINPHONE_PUBLIC size_t linphone_content_get_file_size(const LinphoneContent *content);
/**
* Set the content data size, excluding null character despite null character is always set for convenience.
* @param[in] content #LinphoneContent object
* @param[in] size The content data buffer size.
*/
LINPHONE_PUBLIC void linphone_content_set_size(LinphoneContent *content, size_t size);
LINPHONE_PUBLIC void linphone_content_set_size (LinphoneContent *content, size_t size);
/**
* Get the encoding of the data buffer, for example "gzip".
* @param[in] content #LinphoneContent object.
* @return The encoding of the data buffer.
*/
LINPHONE_PUBLIC const char * linphone_content_get_encoding(const LinphoneContent *content);
LINPHONE_PUBLIC const char *linphone_content_get_encoding (const LinphoneContent *content);
/**
* Set the encoding of the data buffer, for example "gzip".
* @param[in] content #LinphoneContent object.
* @param[in] encoding The encoding of the data buffer.
*/
LINPHONE_PUBLIC void linphone_content_set_encoding(LinphoneContent *content, const char *encoding);
LINPHONE_PUBLIC void linphone_content_set_encoding (LinphoneContent *content, const char *encoding);
/**
* Get the name associated with a RCS file transfer message. It is used to store the original filename of the file to be downloaded from server.
* @param[in] content #LinphoneContent object.
* @return The name of the content.
*/
LINPHONE_PUBLIC const char * linphone_content_get_name(const LinphoneContent *content);
LINPHONE_PUBLIC const char *linphone_content_get_name (const LinphoneContent *content);
/**
* Set the name associated with a RCS file transfer message. It is used to store the original filename of the file to be downloaded from server.
* @param[in] content #LinphoneContent object.
* @param[in] name The name of the content.
*/
LINPHONE_PUBLIC void linphone_content_set_name(LinphoneContent *content, const char *name);
LINPHONE_PUBLIC void linphone_content_set_name (LinphoneContent *content, const char *name);
/**
* Tell whether a content is a multipart content.
* @param[in] content #LinphoneContent object.
* @return A boolean value telling whether the content is multipart or not.
*/
LINPHONE_PUBLIC bool_t linphone_content_is_multipart(const LinphoneContent *content);
LINPHONE_PUBLIC bool_t linphone_content_is_multipart (const LinphoneContent *content);
/**
* Get a part from a multipart content according to its index.
@ -180,7 +191,7 @@ LINPHONE_PUBLIC bool_t linphone_content_is_multipart(const LinphoneContent *cont
* @param[in] idx The index of the part to get.
* @return A #LinphoneContent object holding the part if found, NULL otherwise.
*/
LINPHONE_PUBLIC LinphoneContent * linphone_content_get_part(const LinphoneContent *content, int idx);
LINPHONE_PUBLIC LinphoneContent *linphone_content_get_part (const LinphoneContent *content, int idx);
/**
* Find a part from a multipart content looking for a part header with a specified value.
@ -189,7 +200,11 @@ LINPHONE_PUBLIC LinphoneContent * linphone_content_get_part(const LinphoneConten
* @param[in] header_value The value of the header to look for.
* @return A #LinphoneContent object object the part if found, NULL otherwise.
*/
LINPHONE_PUBLIC LinphoneContent * linphone_content_find_part_by_header(const LinphoneContent *content, const char *header_name, const char *header_value);
LINPHONE_PUBLIC LinphoneContent *linphone_content_find_part_by_header (
const LinphoneContent *content,
const char *header_name,
const char *header_value
);
/**
* Get a custom header value of a content.
@ -197,29 +212,29 @@ LINPHONE_PUBLIC LinphoneContent * linphone_content_find_part_by_header(const Lin
* @param[in] header_name The name of the header to get the value from.
* @return The value of the header if found, NULL otherwise.
*/
LINPHONE_PUBLIC const char * linphone_content_get_custom_header(const LinphoneContent *content, const char *header_name);
LINPHONE_PUBLIC const char *linphone_content_get_custom_header (const LinphoneContent *content, const char *header_name);
/**
* Get the key associated with a RCS file transfer message if encrypted
* @param[in] content #LinphoneContent object.
* @return The key to encrypt/decrypt the file associated to this content.
*/
LINPHONE_PUBLIC const char *linphone_content_get_key(const LinphoneContent *content);
LINPHONE_PUBLIC const char *linphone_content_get_key (const LinphoneContent *content);
/**
* Get the size of key associated with a RCS file transfer message if encrypted
* @param[in] content #LinphoneContent object.
* @return The key size in bytes
*/
LINPHONE_PUBLIC size_t linphone_content_get_key_size(const LinphoneContent *content);
LINPHONE_PUBLIC size_t linphone_content_get_key_size (const LinphoneContent *content);
/**
* Set the key associated with a RCS file transfer message if encrypted
* @param[in] content #LinphoneContent object.
* @param[in] key The key to be used to encrypt/decrypt file associated to this content.
* @param[in] keyLength The lengh of the key.
* @param[in] key_length The lengh of the key.
*/
LINPHONE_PUBLIC void linphone_content_set_key(LinphoneContent *content, const char *key, const size_t keyLength);
LINPHONE_PUBLIC void linphone_content_set_key (LinphoneContent *content, const char *key, const size_t key_length);
/**
* @}
@ -229,4 +244,4 @@ LINPHONE_PUBLIC void linphone_content_set_key(LinphoneContent *content, const ch
}
#endif // ifdef __cplusplus
#endif // ifndef _L_C_CONTENT_H_
#endif // ifndef _L_C_CONTENT_H_

View file

@ -22,9 +22,11 @@
#include "linphone/api/c-types.h"
// =============================================================================
#ifdef __cplusplus
extern "C" {
#endif
extern "C" {
#endif // ifdef __cplusplus
/**
* @addtogroup misc
@ -34,88 +36,88 @@ extern "C" {
/**
* Constructs a LinphoneMagicSearch object
**/
LINPHONE_PUBLIC LinphoneMagicSearch *linphone_magic_search_new(LinphoneCore *lc);
LINPHONE_PUBLIC LinphoneMagicSearch *linphone_magic_search_new (LinphoneCore *lc);
/**
* Increment reference count of LinphoneMagicSearch object.
**/
LINPHONE_PUBLIC LinphoneMagicSearch *linphone_magic_search_ref(LinphoneMagicSearch *magicSearch);
LINPHONE_PUBLIC LinphoneMagicSearch *linphone_magic_search_ref (LinphoneMagicSearch *magic_search);
/**
* Decrement reference count of LinphoneMagicSearch object. When dropped to zero, memory is freed.
**/
LINPHONE_PUBLIC void linphone_magic_search_unref(LinphoneMagicSearch *magicSearch);
LINPHONE_PUBLIC void linphone_magic_search_unref (LinphoneMagicSearch *magic_search);
/**
* Set the minimum value used to calculate the weight in search
* @param[in] weight minimum weight
**/
LINPHONE_PUBLIC void linphone_magic_search_set_min_weight(LinphoneMagicSearch *magicSearch, const unsigned int weight);
LINPHONE_PUBLIC void linphone_magic_search_set_min_weight (LinphoneMagicSearch *magic_search, unsigned int weight);
/**
* @return the minimum value used to calculate the weight in search
**/
LINPHONE_PUBLIC unsigned int linphone_magic_search_get_min_weight(const LinphoneMagicSearch *magicSearch);
LINPHONE_PUBLIC unsigned int linphone_magic_search_get_min_weight (const LinphoneMagicSearch *magic_search);
/**
* Set the maximum value used to calculate the weight in search
* @param[in] weight maximum weight
**/
LINPHONE_PUBLIC void linphone_magic_search_set_max_weight(LinphoneMagicSearch *magicSearch, const unsigned int weight);
LINPHONE_PUBLIC void linphone_magic_search_set_max_weight (LinphoneMagicSearch *magic_search, unsigned int weight);
/**
* @return the maximum value used to calculate the weight in search
**/
LINPHONE_PUBLIC unsigned int linphone_magic_search_get_max_weight(const LinphoneMagicSearch *magicSearch);
LINPHONE_PUBLIC unsigned int linphone_magic_search_get_max_weight (const LinphoneMagicSearch *magic_search);
/**
* @return the delimiter used to find matched filter word
**/
LINPHONE_PUBLIC const char *linphone_magic_search_get_delimiter(const LinphoneMagicSearch *magicSearch);
LINPHONE_PUBLIC const char *linphone_magic_search_get_delimiter (const LinphoneMagicSearch *magic_search);
/**
* Set the delimiter used to find matched filter word
* @param[in] delimiter delimiter (example "-_.,")
**/
LINPHONE_PUBLIC void linphone_magic_search_set_delimiter(LinphoneMagicSearch *magicSearch, const char *delimiter);
LINPHONE_PUBLIC void linphone_magic_search_set_delimiter (LinphoneMagicSearch *magic_search, const char *delimiter);
/**
* @return if the delimiter search is used
**/
LINPHONE_PUBLIC bool_t linphone_magic_search_get_use_delimiter(LinphoneMagicSearch *magicSearch);
LINPHONE_PUBLIC bool_t linphone_magic_search_get_use_delimiter (LinphoneMagicSearch *magic_search);
/**
* Enable or disable the delimiter in search
* @param[in] enable
**/
LINPHONE_PUBLIC void linphone_magic_search_set_use_delimiter(LinphoneMagicSearch *magicSearch, bool_t enable);
LINPHONE_PUBLIC void linphone_magic_search_set_use_delimiter (LinphoneMagicSearch *magic_search, bool_t enable);
/**
* @return the number of the maximum SearchResult which will be return
**/
LINPHONE_PUBLIC unsigned int linphone_magic_search_get_search_limit(const LinphoneMagicSearch *magicSearch);
LINPHONE_PUBLIC unsigned int linphone_magic_search_get_search_limit (const LinphoneMagicSearch *magic_search);
/**
* Set the number of the maximum SearchResult which will be return
* @param[in] limit
**/
LINPHONE_PUBLIC void linphone_magic_search_set_search_limit(LinphoneMagicSearch *magicSearch, const unsigned int limit);
LINPHONE_PUBLIC void linphone_magic_search_set_search_limit (LinphoneMagicSearch *magic_search, unsigned int limit);
/**
* @return if the search is limited
**/
LINPHONE_PUBLIC bool_t linphone_magic_search_get_limited_search(const LinphoneMagicSearch *magicSearch);
LINPHONE_PUBLIC bool_t linphone_magic_search_get_limited_search (const LinphoneMagicSearch *magic_search);
/**
* Enable or disable the limited search
* @param[in] limited
**/
LINPHONE_PUBLIC void linphone_magic_search_set_limited_search(LinphoneMagicSearch *magicSearch, const bool_t limited);
LINPHONE_PUBLIC void linphone_magic_search_set_limited_search (LinphoneMagicSearch *magic_search, bool_t limited);
/**
* Reset the cache to begin a new search
**/
LINPHONE_PUBLIC void linphone_magic_search_reset_search_cache(LinphoneMagicSearch *magicSearch);
LINPHONE_PUBLIC void linphone_magic_search_reset_search_cache (LinphoneMagicSearch *magic_search);
/**
* Create a sorted list of SearchResult from SipUri, Contact name,
@ -124,13 +126,17 @@ LINPHONE_PUBLIC void linphone_magic_search_reset_search_cache(LinphoneMagicSearc
* During the first search, a cache is created and used for the next search
* Use linphone_magic_search_reset_search_cache() to begin a new search
* @param[in] filter word we search
* @param[in] withDomain domain which we want to search only
* @param[in] domain domain which we want to search only
* - "" for searching in all contact
* - "*" for searching in contact with sip SipUri
* - "yourdomain" for searching in contact from "yourdomain" domain
* @return sorted list of \bctbx_list{LinphoneSearchResult}
**/
LINPHONE_PUBLIC bctbx_list_t* linphone_magic_search_get_contact_list_from_filter(LinphoneMagicSearch *magicSearch, const char *filter, const char *withDomain);
LINPHONE_PUBLIC bctbx_list_t* linphone_magic_search_get_contact_list_from_filter (
LinphoneMagicSearch *magic_search,
const char *filter,
const char *domain
);
/**
* @}

View file

@ -177,7 +177,7 @@ LINPHONE_PUBLIC float linphone_call_params_get_sent_framerate(const LinphoneCall
LINPHONE_PUBLIC const LinphoneVideoDefinition * linphone_call_params_get_sent_video_definition(const LinphoneCallParams *cp);
/**
* @biref Gets the size of the video that is sent.
* @brief Gets the size of the video that is sent.
* @param[in] cp #LinphoneCalParams object
* @return The sent video size or MS_VIDEO_SIZE_UNKNOWN if not available.
* @deprecated Use #linphone_call_params_get_sent_video_definition() instead. Deprecated since 2017-03-28.

View file

@ -532,7 +532,7 @@ typedef void (*LinphoneCoreCbsEcCalibrationResultCb)(LinphoneCore *lc, LinphoneE
typedef void (*LinphoneCoreCbsEcCalibrationAudioInitCb)(LinphoneCore *lc);
/**
* @biref Function prototype used by #linphone_core_cbs_set_ec_calibrator_audio_uninit().
* @brief Function prototype used by #linphone_core_cbs_set_ec_calibrator_audio_uninit().
* @param lc The core.
*/
typedef void (*LinphoneCoreCbsEcCalibrationAudioUninitCb)(LinphoneCore *lc);

View file

@ -818,7 +818,7 @@ LINPHONE_PUBLIC char * linphone_core_compress_log_collection(void);
LINPHONE_PUBLIC void linphone_core_reset_log_collection(void);
/**
* @bref Define a log handler.
* @brief Define a log handler.
* @param logfunc The function pointer of the log handler.
* @deprecated Use #linphone_logging_service_cbs_set_log_message_written() instead. Deprecated since 2017-10-10.
* @donotwrap
@ -1289,7 +1289,7 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneStatus linphone_core_decline_call(Li
LINPHONE_PUBLIC LinphoneStatus linphone_core_terminate_all_calls(LinphoneCore *lc);
/**
* @biref Pauses the call. If a music file has been setup using linphone_core_set_play_file(),
* @brief Pauses the call. If a music file has been setup using linphone_core_set_play_file(),
* this file will be played to the remote user.
*
* The only way to resume a paused call is to call linphone_core_resume_call().
@ -3522,7 +3522,7 @@ LINPHONE_PUBLIC LINPHONE_DEPRECATED void linphone_core_set_preferred_video_size(
LINPHONE_PUBLIC void linphone_core_set_preview_video_definition(LinphoneCore *lc, LinphoneVideoDefinition *vdef);
/**
* @biref Sets the video size for the captured (preview) video.
* @brief Sets the video size for the captured (preview) video.
*
* This method is for advanced usage where a video capture must be set independently of the size of the stream actually sent through the call.
* This allows for example to have the preview window with HD resolution even if due to bandwidth constraint the sent video size is small.
@ -4987,6 +4987,15 @@ const char *linphone_core_get_linphone_specs (const LinphoneCore *core);
*/
void linphone_core_set_linphone_specs (LinphoneCore *core, const char *specs);
/**
* Remove support for the specified content type.
* It is the application responsibility to handle it correctly afterwards.
* @param[in] lc LinphoneCore object
* @param[in] content_type The content type to remove support for
*/
LINPHONE_PUBLIC void linphone_core_remove_content_type_support(LinphoneCore *lc, const char *content_type);
/**
* @addtogroup chatroom
* @{

View file

@ -23,18 +23,18 @@
// =============================================================================
#define L_ENUM_VALUES_EVENT_LOG_TYPE(F) \
F(None) \
F(ConferenceCreated) \
F(ConferenceTerminated) \
F(ConferenceCallStart) \
F(ConferenceCallEnd) \
F(ConferenceChatMessage) \
F(ConferenceParticipantAdded) \
F(ConferenceParticipantRemoved) \
F(ConferenceParticipantSetAdmin) \
F(ConferenceParticipantUnsetAdmin) \
F(ConferenceParticipantDeviceAdded) \
F(ConferenceParticipantDeviceRemoved) \
F(ConferenceSubjectChanged)
F(None /**< No defined event */) \
F(ConferenceCreated /**< Conference (created) event */) \
F(ConferenceTerminated /**< Conference (terminated) event */) \
F(ConferenceCallStart /**< Conference call (start) event */) \
F(ConferenceCallEnd /**< Conference call (end) event */) \
F(ConferenceChatMessage /**< Conference chat message event */) \
F(ConferenceParticipantAdded /**< Conference participant (added) event */) \
F(ConferenceParticipantRemoved /**< Conference participant (removed) event */) \
F(ConferenceParticipantSetAdmin /**< Conference participant (set admin) event */) \
F(ConferenceParticipantUnsetAdmin /**< Conference participant (unset admin) event */) \
F(ConferenceParticipantDeviceAdded /**< Conference participant device (added) event */) \
F(ConferenceParticipantDeviceRemoved /**< Conference participant device (removed) event */) \
F(ConferenceSubjectChanged /**< Conference subject event */) \
#endif // ifndef _L_EVENT_LOG_ENUMS_H_

View file

@ -416,7 +416,7 @@ LINPHONE_PUBLIC LinphoneBuffer *linphone_factory_create_buffer_from_string(Linph
/**
* Creates an object #LinphoneConfig
* @param[in] factory the #LinphoneFactory
* @param[in] the path of the config
* @param[in] path the path of the config
* @return a #LinphoneConfig
*/
LINPHONE_PUBLIC LinphoneConfig *linphone_factory_create_config(LinphoneFactory *factory, const char *path);
@ -424,8 +424,8 @@ LINPHONE_PUBLIC LinphoneConfig *linphone_factory_create_config(LinphoneFactory *
/**
* Creates an object #LinphoneConfig
* @param[in] factory the #LinphoneFactory
* @param[in] the path of the config
* @param[in] the path of the factory
* @param[in] path the path of the config
* @param[in] path the path of the factory
* @return a #LinphoneConfig
*/
LINPHONE_PUBLIC LinphoneConfig *linphone_factory_create_config_with_factory(LinphoneFactory *factory, const char *path, const char *factory_path);
@ -433,6 +433,7 @@ LINPHONE_PUBLIC LinphoneConfig *linphone_factory_create_config_with_factory(Linp
/**
* Creates an object #LinphoneConfig
* @param[in] factory the #LinphoneFactory
* @param[in] data the config data
* @return a #LinphoneConfig
*/
LINPHONE_PUBLIC LinphoneConfig *linphone_factory_create_config_from_string(LinphoneFactory *factory, const char *data);
@ -454,17 +455,24 @@ LINPHONE_PUBLIC void linphone_factory_set_user_data(LinphoneFactory *factory, vo
/**
* Sets the log collection path
* @param[in] factory the #LinphoneFactory
* @param[in] the path of the logs
* @param[in] path the path of the logs
*/
LINPHONE_PUBLIC void linphone_factory_set_log_collection_path(LinphoneFactory *factory, const char *path);
/**
* Enables or disables log collection
* @param[in] factory the #LinphoneFactory
* @param[in] the policy for log collection
* @param[in] state the policy for log collection
*/
LINPHONE_PUBLIC void linphone_factory_enable_log_collection(LinphoneFactory *factory, LinphoneLogCollectionState state);
/**
* Creates an object #LinphoneTunnelConfig
* @param[in] factory the #LinphoneFactory
* @return a #LinphoneTunnelConfig
*/
LINPHONE_PUBLIC LinphoneTunnelConfig *linphone_factory_create_tunnel_config(LinphoneFactory *factory);
/**
* @}
*/

View file

@ -22,6 +22,7 @@
#include <ctime>
#include <list>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
@ -107,6 +108,15 @@ namespace Utils {
return str ? str : "";
}
template<typename S, typename T>
LINPHONE_PUBLIC std::string join (const std::vector<T>& elems, const S& delim) {
std::stringstream ss;
auto e = elems.begin();
ss << *e++;
for (; e != elems.end(); ++e)
ss << delim << *e;
return ss.str();
}
LINPHONE_PUBLIC std::string trim (const std::string &str);
template<typename T>

Binary file not shown.

View file

@ -20,6 +20,52 @@
#
############################################################################
set(LIBS
${BCTOOLBOX_CORE_LIBRARIES}
${BELLESIP_LIBRARIES}
${MEDIASTREAMER2_LIBRARIES}
${ORTP_LIBRARIES}
${XML2_LIBRARIES}
${BELR_LIBRARIES}
${LIBXSD_LIBRARIES}
)
if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
list(APPEND LIBS "Ws2_32")
endif()
if(ENABLE_LIME)
list(APPEND LIBS ${BZRTP_LIBRARIES})
endif()
if(ZLIB_FOUND)
list(APPEND LIBS ${ZLIB_LIBRARIES})
endif()
if(SOCI_FOUND)
list(APPEND LIBS ${SOCI_LIBRARIES})
endif()
if(SQLITE3_FOUND)
list(APPEND LIBS ${SQLITE3_LIBRARIES})
endif()
if(ICONV_FOUND)
list(APPEND LIBS ${ICONV_LIBRARIES})
endif()
if(ENABLE_TUNNEL)
list(APPEND LIBS ${TUNNEL_LIBRARIES})
endif()
if(MSVC AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
list(APPEND LIBS ${LIBGCC} ${LIBMINGWEX})
endif()
if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
list(APPEND LIBS shlwapi)
endif()
if(INTL_FOUND)
list(APPEND LIBS ${INTL_LIBRARIES})
endif()
if(BELCARD_FOUND)
list(APPEND LIBS ${BELCARD_LIBRARIES})
endif()
if(ENABLE_TUNNEL)
add_definitions(-DTUNNEL_ENABLED)
endif()
set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
address/address-p.h
address/address.h
@ -35,6 +81,11 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
call/remote-conference-call.h
chat/chat-message/chat-message-p.h
chat/chat-message/chat-message.h
chat/chat-message/imdn-message.h
chat/chat-message/imdn-message-p.h
chat/chat-message/is-composing-message.h
chat/chat-message/notification-message.h
chat/chat-message/notification-message-p.h
chat/chat-room/abstract-chat-room-p.h
chat/chat-room/abstract-chat-room.h
chat/chat-room/basic-chat-room-p.h
@ -157,12 +208,14 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES
sal/sal.h
search/magic-search-p.h
search/magic-search.h
search/search-result-p.h
search/search-result.h
utils/background-task.h
utils/payload-type-handler.h
variant/variant.h
xml/conference-info.h
xml/imdn.h
xml/is-composing.h
xml/linphone-imdn.h
xml/resource-lists.h
xml/rlmi.h
xml/xml.h
@ -194,6 +247,9 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
call/local-conference-call.cpp
call/remote-conference-call.cpp
chat/chat-message/chat-message.cpp
chat/chat-message/imdn-message.cpp
chat/chat-message/is-composing-message.cpp
chat/chat-message/notification-message.cpp
chat/chat-room/abstract-chat-room.cpp
chat/chat-room/basic-chat-room.cpp
chat/chat-room/basic-to-client-group-chat-room.cpp
@ -285,6 +341,9 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES
utils/utils.cpp
variant/variant.cpp
xml/conference-info.cpp
xml/imdn.cpp
xml/is-composing.cpp
xml/linphone-imdn.cpp
xml/resource-lists.cpp
xml/rlmi.cpp
xml/xml.cpp
@ -323,21 +382,98 @@ set(LINPHONE_PRIVATE_HEADER_FILES ${LINPHONE_PRIVATE_HEADER_FILES} PARENT_SCOPE)
bc_apply_compile_flags(LINPHONE_CXX_OBJECTS_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX)
bc_apply_compile_flags(LINPHONE_OBJC_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC)
if (ENABLE_STATIC)
add_library(
linphone-cxx-objects-static OBJECT
${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} ${LINPHONE_OBJC_SOURCE_FILES}
)
target_compile_definitions(linphone-cxx-objects-static PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS})
target_include_directories(linphone-cxx-objects-static SYSTEM PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS})
endif ()
if (ENABLE_SHARED)
add_library(
linphone-cxx-objects OBJECT
if(ENABLE_STATIC)
add_library(linphone-static STATIC ${LINPHONE_HEADER_FILES}
${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} ${LINPHONE_OBJC_SOURCE_FILES}
$<TARGET_OBJECTS:linphone-coreapi-static>
)
target_compile_definitions(linphone-cxx-objects PRIVATE ${LINPHONE_CXX_OBJECTS_DEFINITIONS})
target_include_directories(linphone-cxx-objects SYSTEM PRIVATE ${LINPHONE_CXX_OBJECTS_INCLUDE_DIRS} ${LINPHONE_INCLUDE_DIRS})
target_compile_options(linphone-cxx-objects PRIVATE "-fPIC")
endif ()
set_target_properties(linphone-static PROPERTIES OUTPUT_NAME linphone)
target_include_directories(linphone-static PUBLIC ${LINPHONE_INCLUDE_DIRS})
target_link_libraries(linphone-static INTERFACE ${LIBS})
if(APPLE)
target_link_libraries(linphone-static INTERFACE "-framework Foundation" "-framework AVFoundation")
endif()
install(TARGETS linphone-static EXPORT ${EXPORT_TARGETS_NAME}Targets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
endif()
if(ENABLE_SHARED)
add_library(linphone SHARED "../share/cpim_grammar" ${LINPHONE_HEADER_FILES}
${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES} ${LINPHONE_CXX_OBJECTS_SOURCE_FILES} ${LINPHONE_OBJC_SOURCE_FILES}
$<TARGET_OBJECTS:linphone-coreapi>
)
if(IOS)
if(IOS)
set(MIN_OS ${LINPHONE_IOS_DEPLOYMENT_TARGET})
else()
set(MIN_OS ${CMAKE_OSX_DEPLOYMENT_TARGET})
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/build/osx/")
set_target_properties(linphone PROPERTIES
FRAMEWORK TRUE
MACOSX_FRAMEWORK_IDENTIFIER org.linphone.linphone
MACOSX_FRAMEWORK_INFO_PLIST Info.plist.in
PUBLIC_HEADER "${LINPHONE_HEADER_FILES}"
RESOURCE "../share/cpim_grammar"
)
endif()
if(BELCARD_FOUND)
if(APPLE)
set_target_properties(linphone PROPERTIES LINK_FLAGS "-stdlib=libc++")
endif()
endif()
set_target_properties(linphone PROPERTIES LINKER_LANGUAGE CXX)
if(NOT ANDROID)
# Do not version shared library on Android
set_target_properties(linphone PROPERTIES SOVERSION ${LINPHONE_SO_VERSION})
endif()
target_include_directories(linphone PUBLIC ${LINPHONE_INCLUDE_DIRS})
target_link_libraries(linphone PRIVATE ${LIBS})
if(APPLE)
target_link_libraries(linphone PRIVATE "-framework Foundation" "-framework AVFoundation")
endif()
if(WIN32 AND CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
set_target_properties(linphone PROPERTIES PREFIX "lib")
elseif(ANDROID)
target_link_libraries(linphone PUBLIC "log" ${SUPPORT_LIBRARIES} ${CPUFEATURES_LIBRARIES})
if(ENABLE_JAVA_WRAPPER)
add_dependencies(linphone linphonej)
endif()
endif()
if(MSVC)
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/linphone.pdb
DESTINATION ${CMAKE_INSTALL_BINDIR}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
endif()
endif()
install(TARGETS linphone EXPORT ${EXPORT_TARGETS_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
FRAMEWORK DESTINATION Frameworks
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
endif()
if(ICONV_FOUND)
if(APPLE)
# Prevent conflict between the system iconv.h header and the one from macports.
if(ENABLE_STATIC)
target_compile_options(linphone-static PRIVATE "-include" "${ICONV_INCLUDE_DIRS}/iconv.h")
endif()
if(ENABLE_SHARED)
target_compile_options(linphone PRIVATE "-include" "${ICONV_INCLUDE_DIRS}/iconv.h")
endif()
else()
if(ENABLE_STATIC)
target_include_directories(linphone-static PRIVATE ${ICONV_INCLUDE_DIRS})
endif()
if(ENABLE_SHARED)
target_include_directories(linphone PRIVATE ${ICONV_INCLUDE_DIRS})
endif()
endif()
endif()

View file

@ -37,7 +37,7 @@ LinphoneAddress *linphone_address_new (const char *address) {
LinphoneAddress *object = L_INIT(Address);
L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr);
delete cppPtr;
return object;
}
@ -131,11 +131,11 @@ void linphone_address_clean (LinphoneAddress *address) {
}
char *linphone_address_as_string (const LinphoneAddress *address) {
return ms_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(address)->asString().c_str());
return bctbx_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(address)->asString().c_str());
}
char *linphone_address_as_string_uri_only (const LinphoneAddress *address) {
return ms_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(address)->asStringUriOnly().c_str());
return bctbx_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(address)->asStringUriOnly().c_str());
}
bool_t linphone_address_weak_equal (const LinphoneAddress *address1, const LinphoneAddress *address2) {

View file

@ -34,6 +34,8 @@ struct _LinphoneCallCbs {
LinphoneCallCbsTransferStateChangedCb transferStateChangedCb;
LinphoneCallCbsAckProcessingCb ackProcessing;
LinphoneCallCbsTmmbrReceivedCb tmmbrReceivedCb;
LinphoneCallCbsSnapshotTakenCb snapshotTakenCb;
LinphoneCallCbsNextVideoFrameDecodedCb nextVideoFrameDecodedCb;
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallCbs);
@ -133,3 +135,19 @@ LinphoneCallCbsTmmbrReceivedCb linphone_call_cbs_get_tmmbr_received (LinphoneCal
void linphone_call_cbs_set_tmmbr_received (LinphoneCallCbs *cbs, LinphoneCallCbsTmmbrReceivedCb cb) {
cbs->tmmbrReceivedCb = cb;
}
LinphoneCallCbsSnapshotTakenCb linphone_call_cbs_get_snapshot_taken(LinphoneCallCbs *cbs) {
return cbs->snapshotTakenCb;
}
void linphone_call_cbs_set_snapshot_taken(LinphoneCallCbs *cbs, LinphoneCallCbsSnapshotTakenCb cb) {
cbs->snapshotTakenCb = cb;
}
LinphoneCallCbsNextVideoFrameDecodedCb linphone_call_cbs_get_next_video_frame_decoded(LinphoneCallCbs *cbs) {
return cbs->nextVideoFrameDecodedCb;
}
void linphone_call_cbs_set_next_video_frame_decoded(LinphoneCallCbs *cbs, LinphoneCallCbsNextVideoFrameDecodedCb cb) {
cbs->nextVideoFrameDecodedCb = cb;
}

View file

@ -511,11 +511,9 @@ void linphone_call_params_unref (LinphoneCallParams *cp) {
// =============================================================================
LinphoneCallParams *linphone_call_params_new (LinphoneCore *core) {
LinphoneCallParams *params = _linphone_CallParams_init();
auto mediaSessionParams = new LinphonePrivate::MediaSessionParams();
L_SET_CPP_PTR_FROM_C_OBJECT(params, mediaSessionParams);
LinphoneCallParams *params = L_INIT(CallParams);
L_SET_CPP_PTR_FROM_C_OBJECT(params, new LinphonePrivate::MediaSessionParams());
L_GET_CPP_PTR_FROM_C_OBJECT(params)->initDefault(L_GET_CPP_PTR_FROM_C_OBJECT(core));
delete mediaSessionParams;
return params;
}

View file

@ -43,12 +43,6 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call,
bctbx_list_t *callbacks; /* A list of LinphoneCallCbs object */
LinphoneCallCbs *currentCbs; /* The current LinphoneCallCbs object used to call a callback */
char *authenticationTokenCache;
LinphoneCallParams *currentParamsCache;
LinphoneCallParams *paramsCache;
LinphoneCallParams *remoteParamsCache;
LinphoneAddress *diversionAddressCache;
LinphoneAddress *remoteAddressCache;
LinphoneAddress *toAddressCache;
mutable char *referToCache;
char *remoteContactCache;
char *remoteUserAgentCache;
@ -59,28 +53,9 @@ L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(Call,
LinphoneChatRoom *chat_room;
)
static void _linphone_call_constructor (LinphoneCall *call) {
call->currentParamsCache = linphone_call_params_new_for_wrapper();
call->paramsCache = linphone_call_params_new_for_wrapper();
call->remoteParamsCache = linphone_call_params_new_for_wrapper();
call->diversionAddressCache = linphone_address_new(nullptr);
call->remoteAddressCache = linphone_address_new(nullptr);
call->toAddressCache = linphone_address_new(nullptr);
}
static void _linphone_call_constructor (LinphoneCall *call) {}
static void _linphone_call_destructor (LinphoneCall *call) {
if (call->currentParamsCache)
linphone_call_params_unref(call->currentParamsCache);
if (call->paramsCache)
linphone_call_params_unref(call->paramsCache);
if (call->remoteParamsCache)
linphone_call_params_unref(call->remoteParamsCache);
if (call->diversionAddressCache)
linphone_address_unref(call->diversionAddressCache);
if (call->remoteAddressCache)
linphone_address_unref(call->remoteAddressCache);
if (call->toAddressCache)
linphone_address_unref(call->toAddressCache);
if (call->referToCache)
bctbx_free(call->referToCache);
if (call->remoteContactCache)
@ -92,7 +67,6 @@ static void _linphone_call_destructor (LinphoneCall *call) {
bctbx_list_free_with_data(call->callbacks, (bctbx_list_free_func)linphone_call_cbs_unref);
}
// =============================================================================
// TODO: To remove!
// =============================================================================
@ -210,6 +184,13 @@ void linphone_call_notify_tmmbr_received (LinphoneCall *call, int stream_index,
NOTIFY_IF_EXIST(TmmbrReceived, tmmbr_received, call, stream_index, tmmbr)
}
void linphone_call_notify_snapshot_taken(LinphoneCall *call, const char *file_path) {
NOTIFY_IF_EXIST(SnapshotTaken, snapshot_taken, call, file_path)
}
void linphone_call_notify_next_video_frame_decoded(LinphoneCall *call) {
NOTIFY_IF_EXIST(NextVideoFrameDecoded, next_video_frame_decoded, call)
}
// =============================================================================
// Public functions.
@ -226,18 +207,16 @@ LinphoneCallState linphone_call_get_state (const LinphoneCall *call) {
bool_t linphone_call_asked_to_autoanswer (LinphoneCall *call) {
//return TRUE if the unique(for the moment) incoming call asked to be autoanswered
if (call)
return linphone_call_get_op(call)->autoanswer_asked();
return linphone_call_get_op(call)->autoAnswerAsked();
return FALSE;
}
const LinphoneAddress *linphone_call_get_remote_address (const LinphoneCall *call) {
L_SET_CPP_PTR_FROM_C_OBJECT(call->remoteAddressCache, &L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteAddress());
return call->remoteAddressCache;
return L_GET_C_BACK_PTR(&L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteAddress());
}
const LinphoneAddress *linphone_call_get_to_address (const LinphoneCall *call) {
L_SET_CPP_PTR_FROM_C_OBJECT(call->toAddressCache, &L_GET_CPP_PTR_FROM_C_OBJECT(call)->getToAddress());
return call->toAddressCache;
return L_GET_C_BACK_PTR(&L_GET_CPP_PTR_FROM_C_OBJECT(call)->getToAddress());
}
const char *linphone_call_get_to_header (const LinphoneCall *call, const char *name) {
@ -255,11 +234,8 @@ char *linphone_call_get_remote_address_as_string (const LinphoneCall *call) {
}
const LinphoneAddress *linphone_call_get_diversion_address (const LinphoneCall *call) {
LinphonePrivate::Address diversionAddress(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getDiversionAddress());
if (!diversionAddress.isValid())
return nullptr;
L_SET_CPP_PTR_FROM_C_OBJECT(call->diversionAddressCache, &diversionAddress);
return call->diversionAddressCache;
const LinphonePrivate::Address &diversionAddress = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getDiversionAddress();
return diversionAddress.isValid() ? L_GET_C_BACK_PTR(&diversionAddress) : nullptr;
}
LinphoneCallDir linphone_call_get_dir (const LinphoneCall *call) {
@ -309,17 +285,13 @@ int linphone_call_get_duration (const LinphoneCall *call) {
return L_GET_CPP_PTR_FROM_C_OBJECT(call)->getDuration();
}
const LinphoneCallParams *linphone_call_get_current_params(LinphoneCall *call) {
L_SET_CPP_PTR_FROM_C_OBJECT(call->currentParamsCache, L_GET_CPP_PTR_FROM_C_OBJECT(call)->getCurrentParams());
return call->currentParamsCache;
const LinphoneCallParams *linphone_call_get_current_params (LinphoneCall *call) {
return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getCurrentParams());
}
const LinphoneCallParams *linphone_call_get_remote_params(LinphoneCall *call) {
const LinphonePrivate::MediaSessionParams *remoteParams = L_GET_CPP_PTR_FROM_C_OBJECT(call)->getRemoteParams();
if (!remoteParams)
return nullptr;
L_SET_CPP_PTR_FROM_C_OBJECT(call->remoteParamsCache, remoteParams);
return call->remoteParamsCache;
return remoteParams ? L_GET_C_BACK_PTR(remoteParams) : nullptr;
}
void linphone_call_enable_camera (LinphoneCall *call, bool_t enable) {
@ -603,8 +575,8 @@ void linphone_call_ogl_render (const LinphoneCall *call) {
LinphoneStatus linphone_call_send_info_message (LinphoneCall *call, const LinphoneInfoMessage *info) {
SalBodyHandler *body_handler = sal_body_handler_from_content(linphone_info_message_get_content(info));
linphone_call_get_op(call)->set_sent_custom_header(linphone_info_message_get_headers(info));
return linphone_call_get_op(call)->send_info(nullptr, nullptr, body_handler);
linphone_call_get_op(call)->setSentCustomHeaders(linphone_info_message_get_headers(info));
return linphone_call_get_op(call)->sendInfo(nullptr, nullptr, body_handler);
}
LinphoneCallStats *linphone_call_get_stats (LinphoneCall *call, LinphoneStreamType type) {
@ -645,8 +617,7 @@ void linphone_call_set_params (LinphoneCall *call, const LinphoneCallParams *par
}
const LinphoneCallParams *linphone_call_get_params (LinphoneCall *call) {
L_SET_CPP_PTR_FROM_C_OBJECT(call->paramsCache, L_GET_CPP_PTR_FROM_C_OBJECT(call)->getParams());
return call->paramsCache;
return L_GET_C_BACK_PTR(L_GET_CPP_PTR_FROM_C_OBJECT(call)->getParams());
}
// =============================================================================

View file

@ -43,7 +43,9 @@ static void _linphone_chat_message_constructor (LinphoneChatMessage *msg);
static void _linphone_chat_message_destructor (LinphoneChatMessage *msg);
L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(ChatMessage,
_linphone_chat_message_constructor, _linphone_chat_message_destructor,
_linphone_chat_message_constructor,
_linphone_chat_message_destructor,
LinphoneChatMessageCbs *cbs;
LinphoneAddress *from; // cache for shared_ptr<Address>
LinphoneAddress *to; // cache for shared_ptr<Address>
@ -249,16 +251,8 @@ bool_t linphone_chat_message_is_file_transfer_in_progress(LinphoneChatMessage *m
return L_GET_CPP_PTR_FROM_C_OBJECT(msg)->isFileTransferInProgress();
}
bctbx_list_t *linphone_chat_message_get_participants_that_have_displayed (const LinphoneChatMessage *msg) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsThatHaveDisplayed());
}
bctbx_list_t *linphone_chat_message_get_participants_that_have_not_received (const LinphoneChatMessage *msg) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsThatHaveNotReceived());
}
bctbx_list_t *linphone_chat_message_get_participants_that_have_received (const LinphoneChatMessage *msg) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsThatHaveReceived());
bctbx_list_t *linphone_chat_message_get_participants_by_imdn_state (const LinphoneChatMessage *msg, LinphoneChatMessageState state) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(msg)->getParticipantsByImdnState(LinphonePrivate::ChatMessage::State(state)));
}

View file

@ -21,311 +21,319 @@
#include "linphone/wrapper_utils.h"
#include "c-wrapper/c-wrapper.h"
#include "content/content.h"
#include "content/content-type.h"
#include "content/header/header-param.h"
#include "content/header/header.h"
#include "content/content-manager.h"
#include "content/file-content.h"
#include "content/file-transfer-content.h"
#include "content/header/header-param.h"
// =============================================================================
using namespace std;
L_DECLARE_C_CLONABLE_OBJECT_IMPL(Content,
void *cryptoContext; /**< crypto context used to encrypt file for RCS file transfer */
mutable char *name;
mutable char *type;
mutable char *subtype;
mutable char *body;
mutable size_t size;
mutable char *encoding;
mutable char *key;
static void _linphone_content_constructor (LinphoneContent *content);
static void _linphone_content_destructor (LinphoneContent *content);
L_DECLARE_C_CLONABLE_OBJECT_IMPL_WITH_XTORS(Content,
_linphone_content_constructor,
_linphone_content_destructor,
void *cryptoContext; // Used to encrypt file for RCS file transfer.
mutable size_t size;
struct Cache {
string name;
string type;
string subtype;
string encoding;
string buffer;
} mutable cache;
)
static void _linphone_content_constructor (LinphoneContent *content) {
new(&content->cache) LinphoneContent::Cache();
}
static void _linphone_content_destructor (LinphoneContent *content) {
content->cache.~Cache();
}
// =============================================================================
// Reference and user data handling functions.
// =============================================================================
LinphoneContent * linphone_content_ref(LinphoneContent *content) {
belle_sip_object_ref(content);
LinphoneContent *linphone_content_ref (LinphoneContent *content) {
belle_sip_object_ref(content);
return content;
}
void linphone_content_unref(LinphoneContent *content) {
belle_sip_object_unref(content);
void linphone_content_unref (LinphoneContent *content) {
belle_sip_object_unref(content);
}
void *linphone_content_get_user_data(const LinphoneContent *content) {
return L_GET_USER_DATA_FROM_C_OBJECT(content);
void *linphone_content_get_user_data (const LinphoneContent *content) {
return L_GET_USER_DATA_FROM_C_OBJECT(content);
}
void linphone_content_set_user_data(LinphoneContent *content, void *ud) {
return L_SET_USER_DATA_FROM_C_OBJECT(content, ud);
void linphone_content_set_user_data (LinphoneContent *content, void *user_data) {
return L_SET_USER_DATA_FROM_C_OBJECT(content, user_data);
}
// =============================================================================
const char * linphone_content_get_type(const LinphoneContent *content) {
if (content->type) ms_free(content->type);
content->type = ms_strdup(L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType().getType()));
return content->type;
const char *linphone_content_get_type (const LinphoneContent *content) {
return L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType().getType().c_str();
}
void linphone_content_set_type(LinphoneContent *content, const char *type) {
LinphonePrivate::ContentType ct = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
ct.setType(L_C_TO_STRING(type));
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setContentType(ct);
void linphone_content_set_type (LinphoneContent *content, const char *type) {
LinphonePrivate::ContentType contentType = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
contentType.setType(L_C_TO_STRING(type));
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setContentType(contentType);
}
const char * linphone_content_get_subtype(const LinphoneContent *content) {
if (content->subtype) ms_free(content->subtype);
content->subtype = ms_strdup(L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType().getSubType()));
return content->subtype;
const char *linphone_content_get_subtype (const LinphoneContent *content) {
return L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType().getSubType().c_str();
}
void linphone_content_set_subtype(LinphoneContent *content, const char *subtype) {
LinphonePrivate::ContentType ct = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
ct.setSubType(L_C_TO_STRING(subtype));
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setContentType(ct);
void linphone_content_set_subtype (LinphoneContent *content, const char *subtype) {
LinphonePrivate::ContentType contentType = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
contentType.setSubType(L_C_TO_STRING(subtype));
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setContentType(contentType);
}
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);
void linphone_content_add_content_type_parameter (LinphoneContent *content, const char *name, const char *value) {
LinphonePrivate::ContentType contentType = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
contentType.addParameter(L_C_TO_STRING(name), L_C_TO_STRING(value));
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setContentType(contentType);
}
uint8_t * linphone_content_get_buffer(const LinphoneContent *content) {
return (uint8_t *)linphone_content_get_string_buffer(content);
const uint8_t *linphone_content_get_buffer (const LinphoneContent *content) {
return reinterpret_cast<const uint8_t *>(linphone_content_get_string_buffer(content));
}
void linphone_content_set_buffer(LinphoneContent *content, const uint8_t *buffer, size_t size) {
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setBody(buffer, size);
void linphone_content_set_buffer (LinphoneContent *content, const uint8_t *buffer, size_t size) {
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setBody(buffer, size);
}
const char * linphone_content_get_string_buffer(const LinphoneContent *content) {
if (content->body) ms_free(content->body);
content->body = ms_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(content)->getBodyAsUtf8String().c_str());
return content->body;
const char *linphone_content_get_string_buffer (const LinphoneContent *content) {
content->cache.buffer = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getBodyAsUtf8String();
return content->cache.buffer.c_str();
}
void linphone_content_set_string_buffer(LinphoneContent *content, const char *buffer) {
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setBodyFromUtf8(L_C_TO_STRING(buffer));
void linphone_content_set_string_buffer (LinphoneContent *content, const char *buffer) {
L_GET_CPP_PTR_FROM_C_OBJECT(content)->setBodyFromUtf8(L_C_TO_STRING(buffer));
}
size_t linphone_content_get_size(const LinphoneContent *content) {
size_t size = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getSize();
if (size == 0) {
size = content->size;
}
return size;
size_t linphone_content_get_file_size(const LinphoneContent *content) {
const LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
size_t size = 0;
if (c->isFile())
size = static_cast<const LinphonePrivate::FileContent *>(c)->getFileSize();
else if (c->isFileTransfer())
size = static_cast<const LinphonePrivate::FileTransferContent *>(c)->getFileSize();
return size;
}
void linphone_content_set_size(LinphoneContent *content, size_t size) {
content->size = size;
size_t linphone_content_get_size (const LinphoneContent *content) {
const LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
size_t size = c->getSize();
if (size == 0) {
size = content->size;
}
return size;
}
const char * linphone_content_get_encoding(const LinphoneContent *content) {
return content->encoding;
void linphone_content_set_size (LinphoneContent *content, size_t size) {
content->size = size;
}
void linphone_content_set_encoding(LinphoneContent *content, const char *encoding) {
if (content->encoding) ms_free(content->encoding);
content->encoding = ms_strdup(encoding);
const char *linphone_content_get_encoding (const LinphoneContent *content) {
return content->cache.encoding.c_str();
}
const char * linphone_content_get_name(const LinphoneContent *content) {
const LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFile()) {
const LinphonePrivate::FileContent *fc = static_cast<const LinphonePrivate::FileContent *>(c);
if (content->name) ms_free(content->name);
content->name = ms_strdup(L_STRING_TO_C(fc->getFileName()));
} else if (c->isFileTransfer()) {
const LinphonePrivate::FileTransferContent *ftc = static_cast<const LinphonePrivate::FileTransferContent *>(c);
if (content->name) ms_free(content->name);
content->name = ms_strdup(L_STRING_TO_C(ftc->getFileName()));
}
return content->name;
void linphone_content_set_encoding (LinphoneContent *content, const char *encoding) {
content->cache.encoding = L_C_TO_STRING(encoding);
}
void linphone_content_set_name(LinphoneContent *content, const char *name) {
if (content->name) ms_free(content->name);
LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFile()) {
LinphonePrivate::FileContent *fc = static_cast<LinphonePrivate::FileContent *>(c);
fc->setFileName(L_C_TO_STRING(name));
} else if (c->isFileTransfer()) {
LinphonePrivate::FileTransferContent *ftc = static_cast<LinphonePrivate::FileTransferContent *>(c);
ftc->setFileName(L_C_TO_STRING(name));
}
content->name = ms_strdup(name);
const char *linphone_content_get_name (const LinphoneContent *content) {
const LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFile())
return static_cast<const LinphonePrivate::FileContent *>(c)->getFileName().c_str();
if (c->isFileTransfer())
return static_cast<const LinphonePrivate::FileTransferContent *>(c)->getFileName().c_str();
return content->cache.name.c_str();
}
bool_t linphone_content_is_multipart(const LinphoneContent *content) {
return L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType().isMultipart();
void linphone_content_set_name (LinphoneContent *content, const char *name) {
LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFile())
static_cast<LinphonePrivate::FileContent *>(c)->setFileName(L_C_TO_STRING(name));
else if (c->isFileTransfer())
static_cast<LinphonePrivate::FileTransferContent *>(c)->setFileName(L_C_TO_STRING(name));
else
content->cache.name = L_C_TO_STRING(name);
}
LinphoneContent * linphone_content_get_part(const LinphoneContent *content, int idx) {
bool_t linphone_content_is_multipart (const LinphoneContent *content) {
return L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType().isMultipart();
}
LinphoneContent *linphone_content_get_part (const LinphoneContent *content, int idx) {
SalBodyHandler *part_body_handler;
SalBodyHandler *body_handler = sal_body_handler_from_content(content);
if (!sal_body_handler_is_multipart(body_handler)) {
sal_body_handler_unref(body_handler);
return NULL;
}
if (!sal_body_handler_is_multipart(body_handler)) {
sal_body_handler_unref(body_handler);
return NULL;
}
part_body_handler = sal_body_handler_get_part(body_handler, idx);
LinphoneContent *result = linphone_content_from_sal_body_handler(part_body_handler);
sal_body_handler_unref(body_handler);
return result;
sal_body_handler_unref(body_handler);
return result;
}
LinphoneContent * linphone_content_find_part_by_header(const LinphoneContent *content, const char *header_name, const char *header_value) {
LinphoneContent *linphone_content_find_part_by_header (const LinphoneContent *content, const char *header_name, const char *header_value) {
SalBodyHandler *part_body_handler;
SalBodyHandler *body_handler = sal_body_handler_from_content(content);
if (!sal_body_handler_is_multipart(body_handler)) {
sal_body_handler_unref(body_handler);
return NULL;
}
if (!sal_body_handler_is_multipart(body_handler)) {
sal_body_handler_unref(body_handler);
return NULL;
}
part_body_handler = sal_body_handler_find_part_by_header(body_handler, header_name, header_value);
LinphoneContent *result = linphone_content_from_sal_body_handler(part_body_handler);
sal_body_handler_unref(body_handler);
return result;
LinphoneContent *result = linphone_content_from_sal_body_handler(part_body_handler);
sal_body_handler_unref(body_handler);
return result;
}
const char * linphone_content_get_custom_header(const LinphoneContent *content, const char *header_name) {
SalBodyHandler *body_handler = sal_body_handler_from_content(content);
const char *header = sal_body_handler_get_header(body_handler, header_name);
sal_body_handler_unref(body_handler);
return header;
const char *linphone_content_get_custom_header (const LinphoneContent *content, const char *header_name) {
SalBodyHandler *body_handler = sal_body_handler_from_content(content);
const char *header = sal_body_handler_get_header(body_handler, header_name);
sal_body_handler_unref(body_handler);
return header;
}
const char *linphone_content_get_key(const LinphoneContent *content) {
if (content->key) ms_free(content->key);
const LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFileTransfer()) {
const LinphonePrivate::FileTransferContent *ftc = static_cast<const LinphonePrivate::FileTransferContent *>(c);
content->key = ms_strdup(ftc->getFileKeyAsString());
}
return content->key;
const char *linphone_content_get_key (const LinphoneContent *content) {
const LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFileTransfer()) {
const LinphonePrivate::FileTransferContent *ftc = static_cast<const LinphonePrivate::FileTransferContent *>(c);
return ftc->getFileKey().data();
}
return nullptr;
}
size_t linphone_content_get_key_size(const LinphoneContent *content) {
const LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFileTransfer()) {
const LinphonePrivate::FileTransferContent *ftc = static_cast<const LinphonePrivate::FileTransferContent *>(c);
return ftc->getFileKeySize();
}
return 0;
size_t linphone_content_get_key_size (const LinphoneContent *content) {
const LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFileTransfer()) {
const LinphonePrivate::FileTransferContent *ftc = static_cast<const LinphonePrivate::FileTransferContent *>(c);
return ftc->getFileKeySize();
}
return 0;
}
void linphone_content_set_key(LinphoneContent *content, const char *key, const size_t keyLength) {
LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFileTransfer()) {
LinphonePrivate::FileTransferContent *ftc = static_cast<LinphonePrivate::FileTransferContent *>(c);
ftc->setFileKey(key, keyLength);
}
void linphone_content_set_key (LinphoneContent *content, const char *key, const size_t key_length) {
LinphonePrivate::Content *c = L_GET_CPP_PTR_FROM_C_OBJECT(content);
if (c->isFileTransfer()) {
LinphonePrivate::FileTransferContent *ftc = static_cast<LinphonePrivate::FileTransferContent *>(c);
ftc->setFileKey(key, key_length);
}
}
// =============================================================================
// Private functions.
// =============================================================================
static LinphoneContent * linphone_content_new_with_body_handler(SalBodyHandler *body_handler) {
static LinphoneContent *linphone_content_new_with_body_handler (const SalBodyHandler *body_handler) {
LinphoneContent *content = L_INIT(Content);
content->cryptoContext = NULL;
LinphonePrivate::Content *c = new LinphonePrivate::Content();
L_SET_CPP_PTR_FROM_C_OBJECT(content, c);
content->cryptoContext = NULL;
LinphonePrivate::Content *c = new LinphonePrivate::Content();
L_SET_CPP_PTR_FROM_C_OBJECT(content, c);
if (body_handler != NULL) {
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 (body_handler != NULL) {
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 (!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);
char *body = belle_sip_object_to_string(mpbh);
linphone_content_set_string_buffer(content, body);
belle_sip_free(body);
}
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);
char *body = belle_sip_object_to_string(mpbh);
linphone_content_set_string_buffer(content, body);
belle_sip_free(body);
}
belle_sip_list_t *headers = (belle_sip_list_t *)sal_body_handler_get_headers(body_handler);
while (headers) {
belle_sip_header_t *cHeader = BELLE_SIP_HEADER(headers->data);
LinphonePrivate::Header header = LinphonePrivate::Header(belle_sip_header_get_name(cHeader), belle_sip_header_get_unparsed_value(cHeader));
L_GET_CPP_PTR_FROM_C_OBJECT(content)->addHeader(header);
headers = headers->next;
}
if (sal_body_handler_get_encoding(body_handler)) linphone_content_set_encoding(content, sal_body_handler_get_encoding(body_handler));
belle_sip_list_t *headers = (belle_sip_list_t *)sal_body_handler_get_headers(body_handler);
while (headers) {
belle_sip_header_t *cHeader = BELLE_SIP_HEADER(headers->data);
LinphonePrivate::Header header = LinphonePrivate::Header(belle_sip_header_get_name(cHeader), belle_sip_header_get_unparsed_value(cHeader));
L_GET_CPP_PTR_FROM_C_OBJECT(content)->addHeader(header);
headers = headers->next;
}
if (sal_body_handler_get_encoding(body_handler)) linphone_content_set_encoding(content, sal_body_handler_get_encoding(body_handler));
}
return content;
return content;
}
LinphoneContent * linphone_content_new(void) {
LinphoneContent *linphone_content_new (void) {
return linphone_content_new_with_body_handler(NULL);
}
LinphoneContent * linphone_content_copy(const LinphoneContent *ref) {
return (LinphoneContent *)(belle_sip_object_clone(BELLE_SIP_OBJECT(ref)));
LinphoneContent *linphone_content_copy (const LinphoneContent *ref) {
return (LinphoneContent *)belle_sip_object_clone(BELLE_SIP_OBJECT(ref));
}
LinphoneContent * linphone_core_create_content(LinphoneCore *lc) {
LinphoneContent *linphone_core_create_content (LinphoneCore *lc) {
return linphone_content_new();
}
/* crypto context is managed(allocated/freed) by the encryption function, so provide the address of field in the private structure */
void ** linphone_content_get_cryptoContext_address(LinphoneContent *content) {
return &(content->cryptoContext);
// Crypto context is managed(allocated/freed) by the encryption function,
// so provide the address of field in the private structure.
void **linphone_content_get_cryptoContext_address (LinphoneContent *content) {
return &content->cryptoContext;
}
LinphoneContent * linphone_content_from_sal_body_handler(SalBodyHandler *body_handler) {
LinphoneContent *linphone_content_from_sal_body_handler (const SalBodyHandler *body_handler) {
if (body_handler) {
return linphone_content_new_with_body_handler(body_handler);
}
return NULL;
}
SalBodyHandler * sal_body_handler_from_content(const LinphoneContent *content, bool parseMultipart) {
SalBodyHandler *sal_body_handler_from_content (const LinphoneContent *content, bool parseMultipart) {
if (content == NULL) return NULL;
SalBodyHandler *body_handler;
LinphonePrivate::ContentType contentType = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
SalBodyHandler *body_handler;
LinphonePrivate::ContentType contentType = L_GET_CPP_PTR_FROM_C_OBJECT(content)->getContentType();
if (contentType.isMultipart() && parseMultipart) {
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("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 {
body_handler = sal_body_handler_new();
sal_body_handler_set_data(body_handler, belle_sip_strdup(linphone_content_get_string_buffer(content)));
}
if (contentType.isMultipart() && parseMultipart) {
size_t size = linphone_content_get_size(content);
char *buffer = bctbx_strdup(L_GET_CPP_PTR_FROM_C_OBJECT(content)->getBodyAsUtf8String().c_str());
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);
bctbx_free(buffer);
} else {
body_handler = sal_body_handler_new();
sal_body_handler_set_data(body_handler, belle_sip_strdup(linphone_content_get_string_buffer(content)));
}
for (const auto &header : L_GET_CPP_PTR_FROM_C_OBJECT(content)->getHeaders()) {
belle_sip_header_t *additionalHeader = belle_sip_header_parse(header.asString().c_str());
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), additionalHeader);
}
for (const auto &header : L_GET_CPP_PTR_FROM_C_OBJECT(content)->getHeaders()) {
belle_sip_header_t *additionalHeader = belle_sip_header_parse(header.asString().c_str());
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), additionalHeader);
}
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));
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));
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));
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->cache.encoding.empty())
sal_body_handler_set_encoding(body_handler, linphone_content_get_encoding(content));
return body_handler;
}

View file

@ -17,15 +17,19 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "search/magic-search.h"
#include "c-wrapper/c-wrapper.h"
#include "search/magic-search.h"
// =============================================================================
using namespace std;
L_DECLARE_C_OBJECT_IMPL(MagicSearch);
LinphoneMagicSearch *linphone_core_create_magic_search(LinphoneCore *lc) {
shared_ptr<LinphonePrivate::MagicSearch> cppPtr = make_shared<LinphonePrivate::MagicSearch>(L_GET_CPP_PTR_FROM_C_OBJECT(lc));
shared_ptr<LinphonePrivate::MagicSearch> cppPtr = make_shared<LinphonePrivate::MagicSearch>(
L_GET_CPP_PTR_FROM_C_OBJECT(lc)
);
LinphoneMagicSearch *object = L_INIT(MagicSearch);
L_SET_CPP_PTR_FROM_C_OBJECT(object, cppPtr);
@ -36,67 +40,73 @@ LinphoneMagicSearch *linphone_magic_search_new(LinphoneCore *lc) {
return linphone_core_create_magic_search(lc);
}
LinphoneMagicSearch *linphone_magic_search_ref(LinphoneMagicSearch *magicSearch) {
belle_sip_object_ref(magicSearch);
return magicSearch;
LinphoneMagicSearch *linphone_magic_search_ref (LinphoneMagicSearch *magic_search) {
belle_sip_object_ref(magic_search);
return magic_search;
}
void linphone_magic_search_unref(LinphoneMagicSearch *magicSearch) {
belle_sip_object_unref(magicSearch);
void linphone_magic_search_unref (LinphoneMagicSearch *magic_search) {
belle_sip_object_unref(magic_search);
}
void linphone_magic_search_set_min_weight(LinphoneMagicSearch *magicSearch, const unsigned int weight) {
L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->setMinWeight(weight);
void linphone_magic_search_set_min_weight (LinphoneMagicSearch *magic_search, unsigned int weight) {
L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->setMinWeight(weight);
}
unsigned int linphone_magic_search_get_min_weight(const LinphoneMagicSearch *magicSearch) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->getMinWeight();
unsigned int linphone_magic_search_get_min_weight (const LinphoneMagicSearch *magic_search) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->getMinWeight();
}
void linphone_magic_search_set_max_weight(LinphoneMagicSearch *magicSearch, const unsigned int weight) {
L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->setMaxWeight(weight);
void linphone_magic_search_set_max_weight (LinphoneMagicSearch *magic_search, unsigned int weight) {
L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->setMaxWeight(weight);
}
unsigned int linphone_magic_search_get_max_weight(const LinphoneMagicSearch *magicSearch) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->getMaxWeight();
unsigned int linphone_magic_search_get_max_weight (const LinphoneMagicSearch *magic_search) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->getMaxWeight();
}
const char *linphone_magic_search_get_delimiter(const LinphoneMagicSearch *magicSearch) {
return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->getDelimiter());
const char *linphone_magic_search_get_delimiter (const LinphoneMagicSearch *magic_search) {
return L_STRING_TO_C(L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->getDelimiter());
}
void linphone_magic_search_set_delimiter(LinphoneMagicSearch *magicSearch, const char *delimiter) {
L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->setDelimiter(L_C_TO_STRING(delimiter));
void linphone_magic_search_set_delimiter (LinphoneMagicSearch *magic_search, const char *delimiter) {
L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->setDelimiter(L_C_TO_STRING(delimiter));
}
bool_t linphone_magic_search_get_use_delimiter(LinphoneMagicSearch *magicSearch) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->getUseDelimiter();
bool_t linphone_magic_search_get_use_delimiter (LinphoneMagicSearch *magic_search) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->getUseDelimiter();
}
void linphone_magic_search_set_use_delimiter(LinphoneMagicSearch *magicSearch, bool_t enable) {
L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->setUseDelimiter(enable);
void linphone_magic_search_set_use_delimiter (LinphoneMagicSearch *magic_search, bool_t enable) {
L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->setUseDelimiter(enable);
}
unsigned int linphone_magic_search_get_search_limit(const LinphoneMagicSearch *magicSearch) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->getSearchLimit();
unsigned int linphone_magic_search_get_search_limit (const LinphoneMagicSearch *magic_search) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->getSearchLimit();
}
void linphone_magic_search_set_search_limit(LinphoneMagicSearch *magicSearch, const unsigned int limit) {
L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->setSearchLimit(limit);
void linphone_magic_search_set_search_limit (LinphoneMagicSearch *magic_search, unsigned int limit) {
L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->setSearchLimit(limit);
}
bool_t linphone_magic_search_get_limited_search(const LinphoneMagicSearch *magicSearch) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->getLimitedSearch();
bool_t linphone_magic_search_get_limited_search (const LinphoneMagicSearch *magic_search) {
return L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->getLimitedSearch();
}
void linphone_magic_search_set_limited_search(LinphoneMagicSearch *magicSearch, const bool_t limited) {
L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->setLimitedSearch(limited);
void linphone_magic_search_set_limited_search (LinphoneMagicSearch *magic_search, bool_t limited) {
L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->setLimitedSearch(limited);
}
void linphone_magic_search_reset_search_cache(LinphoneMagicSearch *magicSearch) {
L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->resetSearchCache();
void linphone_magic_search_reset_search_cache (LinphoneMagicSearch *magic_search) {
L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->resetSearchCache();
}
bctbx_list_t* linphone_magic_search_get_contact_list_from_filter(LinphoneMagicSearch *magicSearch, const char *filter, const char *withDomain) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(magicSearch)->getContactListFromFilter(L_C_TO_STRING(filter), L_C_TO_STRING(withDomain)));
bctbx_list_t* linphone_magic_search_get_contact_list_from_filter (
LinphoneMagicSearch *magic_search,
const char *filter,
const char *domain
) {
return L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(L_GET_CPP_PTR_FROM_C_OBJECT(magic_search)->getContactListFromFilter(
L_C_TO_STRING(filter), L_C_TO_STRING(domain)
));
}

View file

@ -140,6 +140,9 @@ private:
struct WrappedClonableObject {
belle_sip_object_t base;
CppType *cppPtr;
// By default: External.
WrappedObjectOwner owner;
};
// ---------------------------------------------------------------------------
@ -236,7 +239,7 @@ public:
: wrappedObject->cppPtr;
if (cppObject)
cppObject->setCBackPtr(nullptr); \
cppObject->setCBackPtr(nullptr);
wrappedObject->cppPtr.~shared_ptr();
wrappedObject->weakCppPtr.~weak_ptr();
@ -248,7 +251,9 @@ public:
typename = typename std::enable_if<IsDefinedClonableCppObject<CppType>::value, CppType>::type
>
static void uninitClonableCppObject (CType *cObject) {
delete reinterpret_cast<WrappedClonableObject<CppType> *>(cObject)->cppPtr;
WrappedClonableObject<CppType> *wrappedObject = reinterpret_cast<WrappedClonableObject<CppType> *>(cObject);
if (wrappedObject->owner == WrappedObjectOwner::External)
delete wrappedObject->cppPtr;
}
// ---------------------------------------------------------------------------
@ -288,12 +293,22 @@ public:
typename CppType,
typename = typename std::enable_if<std::is_base_of<BaseObject, CppType>::value, CppType>::type
>
static void signalCppPtrDestruction (CppType *cppObject) {
static void handleObjectDestruction (CppType *cppObject) {
void *value = cppObject->getCBackPtr();
if (value && static_cast<WrappedBaseObject<CppType> *>(value)->owner == WrappedObjectOwner::Internal)
belle_sip_object_unref(value);
}
template<
typename CppType,
typename = typename std::enable_if<std::is_base_of<ClonableObject, CppType>::value, CppType>::type
>
static void handleClonableObjectDestruction (CppType *cppObject) {
void *value = cppObject->getCBackPtr();
if (value && static_cast<WrappedClonableObject<CppType> *>(value)->owner == WrappedObjectOwner::Internal)
belle_sip_object_unref(value);
}
// ---------------------------------------------------------------------------
// Get c/cpp ptr helpers.
// ---------------------------------------------------------------------------
@ -413,11 +428,13 @@ public:
typename CppType = typename CTypeMetaInfo<CType>::cppType,
typename = typename std::enable_if<IsDefinedClonableCppObject<CppType>::value, CppType>::type
>
static inline void setCppPtrFromC (CType *cObject, CppType* &&cppObject) {
static inline void setCppPtrFromC (CType *cObject, CppType *cppObject) {
CppType **cppObjectAddr = &reinterpret_cast<WrappedClonableObject<CppType> *>(cObject)->cppPtr;
if (*cppObjectAddr == cppObject)
return;
delete *cppObjectAddr;
if (reinterpret_cast<WrappedClonableObject<CppType> *>(cObject)->owner == WrappedObjectOwner::External)
delete *cppObjectAddr;
*cppObjectAddr = cppObject;
(*cppObjectAddr)->setCBackPtr(cObject);
@ -427,15 +444,6 @@ public:
#endif
}
template<
typename CType,
typename CppType = typename CTypeMetaInfo<CType>::cppType,
typename = typename std::enable_if<IsDefinedClonableCppObject<CppType>::value, CppType>::type
>
static inline void setCppPtrFromC (CType *cObject, const CppType *cppObject) {
setCppPtrFromC(cObject, new CppType(*cppObject));
}
// ---------------------------------------------------------------------------
// Get c back ptr resolver helpers.
// ---------------------------------------------------------------------------
@ -464,7 +472,8 @@ private:
return static_cast<RetType *>(value);
RetType *cObject = CppTypeMetaInfo<CppType>::init();
setCppPtrFromC(cObject, cppObject);
reinterpret_cast<WrappedClonableObject<CppType> *>(cObject)->owner = WrappedObjectOwner::Internal;
setCppPtrFromC(cObject, const_cast<CppType *>(cppObject));
return cObject;
}
@ -500,7 +509,6 @@ public:
RetType *cObject = CppTypeMetaInfo<CppType>::init();
reinterpret_cast<WrappedBaseObject<CppType> *>(cObject)->owner = WrappedObjectOwner::Internal;
setCppPtrFromC(cObject, cppObject);
return cObject;
@ -561,8 +569,11 @@ public:
>
static inline bctbx_list_t *getResolvedCListFromCppList (const std::list<CppType> &cppList) {
bctbx_list_t *result = nullptr;
for (const auto &value : cppList)
result = bctbx_list_append(result, getCBackPtr(&value));
for (const auto &value : cppList) {
auto cValue = getCBackPtr(new CppType(value));
reinterpret_cast<WrappedClonableObject<CppType> *>(cValue)->owner = WrappedObjectOwner::External;
result = bctbx_list_append(result, cValue);
}
return result;
}
@ -600,9 +611,9 @@ LINPHONE_END_NAMESPACE
#undef L_INTERNAL_WRAPPER_CONSTEXPR
#define L_INTERNAL_C_OBJECT_NO_XTOR(C_OBJECT)
#define L_INTERNAL_C_NO_XTOR(C_OBJECT)
#define L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, CPP_TYPE, ...) \
#define L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, ...) \
static_assert(LinphonePrivate::CTypeMetaInfo<Linphone ## C_TYPE>::defined, "Type is not defined."); \
static_assert( \
LinphonePrivate::IsDefinedBaseCppObject< \
@ -621,13 +632,13 @@ LINPHONE_END_NAMESPACE
#define L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) \
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \
Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init () { \
Linphone ## C_TYPE * object = belle_sip_object_new(Linphone ## C_TYPE); \
Linphone ## C_TYPE *object = belle_sip_object_new(Linphone ## C_TYPE); \
new(&object->cppPtr) std::shared_ptr<L_CPP_TYPE_OF_C_TYPE(C_TYPE)>(); \
new(&object->weakCppPtr) std::weak_ptr<L_CPP_TYPE_OF_C_TYPE(C_TYPE)>(); \
CONSTRUCTOR(object); \
return object; \
} \
static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE *object) { \
static void _linphone_ ## C_TYPE ## _uninit (Linphone ## C_TYPE *object) { \
DESTRUCTOR(object); \
LinphonePrivate::Wrapper::uninitBaseCppObject(object); \
} \
@ -643,6 +654,45 @@ LINPHONE_END_NAMESPACE
FALSE \
);
#define L_INTERNAL_DECLARE_C_CLONABLE_OBJECT(C_TYPE, ...) \
static_assert(LinphonePrivate::CTypeMetaInfo<Linphone ## C_TYPE>::defined, "Type is not defined."); \
static_assert( \
LinphonePrivate::IsDefinedClonableCppObject< \
LinphonePrivate::CTypeMetaInfo<Linphone ## C_TYPE>::cppType \
>::value, \
"Type is not declared as clonable object." \
); \
struct _Linphone ## C_TYPE { \
belle_sip_object_t base; \
L_CPP_TYPE_OF_C_TYPE(C_TYPE) *cppPtr; \
int owner; \
__VA_ARGS__ \
}; \
#define L_INTERNAL_DECLARE_C_CLONABLE_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR) \
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \
Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init () { \
Linphone ## C_TYPE *object = belle_sip_object_new(Linphone ## C_TYPE); \
CONSTRUCTOR(object); \
return object; \
} \
static void _linphone_ ## C_TYPE ## _uninit (Linphone ## C_TYPE * object) { \
DESTRUCTOR(object); \
LinphonePrivate::Wrapper::uninitClonableCppObject(object); \
} \
static void _linphone_ ## C_TYPE ## _clone (Linphone ## C_TYPE *dest, const Linphone ## C_TYPE *src) { \
L_ASSERT(src->cppPtr); \
dest->cppPtr = new L_CPP_TYPE_OF_C_TYPE(C_TYPE)(*src->cppPtr); \
} \
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \
BELLE_SIP_INSTANCIATE_VPTR( \
Linphone ## C_TYPE, belle_sip_object_t, \
_linphone_ ## C_TYPE ## _uninit, \
_linphone_ ## C_TYPE ## _clone, \
NULL, \
FALSE \
);
// =============================================================================
// Public Wrapper API.
// =============================================================================
@ -702,47 +752,23 @@ LINPHONE_END_NAMESPACE
// Declare wrapped C object with constructor/destructor.
#define L_DECLARE_C_OBJECT_IMPL_WITH_XTORS(C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \
L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, L_CPP_TYPE_OF_C_TYPE(C_TYPE), __VA_ARGS__) \
L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, __VA_ARGS__) \
L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR)
// Declare wrapped C object.
#define L_DECLARE_C_OBJECT_IMPL(C_TYPE, ...) \
L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, L_CPP_TYPE_OF_C_TYPE(C_TYPE), __VA_ARGS__) \
L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, L_INTERNAL_C_OBJECT_NO_XTOR, L_INTERNAL_C_OBJECT_NO_XTOR)
L_INTERNAL_DECLARE_C_OBJECT(C_TYPE, __VA_ARGS__) \
L_INTERNAL_DECLARE_C_OBJECT_FUNCTIONS(C_TYPE, L_INTERNAL_C_NO_XTOR, L_INTERNAL_C_NO_XTOR)
// Declare clonable wrapped C object with constructor/destructor.
#define L_DECLARE_C_CLONABLE_OBJECT_IMPL_WITH_XTORS(C_TYPE, CONSTRUCTOR, DESTRUCTOR, ...) \
L_INTERNAL_DECLARE_C_CLONABLE_OBJECT(C_TYPE, __VA_ARGS__) \
L_INTERNAL_DECLARE_C_CLONABLE_OBJECT_FUNCTIONS(C_TYPE, CONSTRUCTOR, DESTRUCTOR)
// Declare clonable wrapped C object.
#define L_DECLARE_C_CLONABLE_OBJECT_IMPL(C_TYPE, ...) \
static_assert(LinphonePrivate::CTypeMetaInfo<Linphone ## C_TYPE>::defined, "Type is not defined."); \
static_assert( \
LinphonePrivate::IsDefinedClonableCppObject< \
LinphonePrivate::CTypeMetaInfo<Linphone ## C_TYPE>::cppType \
>::value, \
"Type is not declared as clonable object." \
); \
struct _Linphone ## C_TYPE { \
belle_sip_object_t base; \
L_CPP_TYPE_OF_C_TYPE(C_TYPE) *cppPtr; \
__VA_ARGS__ \
}; \
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(Linphone ## C_TYPE); \
Linphone ## C_TYPE *_linphone_ ## C_TYPE ## _init() { \
return belle_sip_object_new(Linphone ## C_TYPE); \
} \
static void _linphone_ ## C_TYPE ## _uninit(Linphone ## C_TYPE * object) { \
LinphonePrivate::Wrapper::uninitClonableCppObject(object); \
} \
static void _linphone_ ## C_TYPE ## _clone(Linphone ## C_TYPE * dest, const Linphone ## C_TYPE * src) { \
L_ASSERT(src->cppPtr); \
dest->cppPtr = new L_CPP_TYPE_OF_C_TYPE(C_TYPE)(*src->cppPtr); \
} \
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(Linphone ## C_TYPE); \
BELLE_SIP_INSTANCIATE_VPTR( \
Linphone ## C_TYPE, belle_sip_object_t, \
_linphone_ ## C_TYPE ## _uninit, \
_linphone_ ## C_TYPE ## _clone, \
NULL, \
FALSE \
);
L_INTERNAL_DECLARE_C_CLONABLE_OBJECT(C_TYPE, __VA_ARGS__) \
L_INTERNAL_DECLARE_C_CLONABLE_OBJECT_FUNCTIONS(C_TYPE, L_INTERNAL_C_NO_XTOR, L_INTERNAL_C_NO_XTOR)
// -----------------------------------------------------------------------------
// Helpers.
@ -755,10 +781,6 @@ LINPHONE_END_NAMESPACE
// Call the init function of wrapped C object.
#define L_INIT(C_TYPE) _linphone_ ## C_TYPE ## _init()
// Signal to wrapper the destruction of cpp base object.
#define L_SIGNAL_CPP_PTR_DESTRUCTION(CPP_OBJECT) \
LinphonePrivate::Wrapper::signalCppPtrDestruction(CPP_OBJECT);
// Get/set the cpp-ptr of a wrapped C object.
#define L_GET_CPP_PTR_FROM_C_OBJECT_1_ARGS(C_OBJECT) \
LinphonePrivate::Wrapper::getCppPtrFromC(C_OBJECT)

View file

@ -111,6 +111,7 @@ private:
bool isPlayingRingbackTone (const std::shared_ptr<CallSession> &session) override;
void onRealTimeTextCharacterReceived (const std::shared_ptr<CallSession> &session, RealtimeTextReceivedCharacter *character) override;
void onTmmbrReceived(const std::shared_ptr<CallSession> &session, int streamIndex, int tmmbr) override;
void onSnapshotTaken(const std::shared_ptr<CallSession> &session, const char *file_path) override;
mutable LinphonePlayer *player = nullptr;

View file

@ -41,10 +41,8 @@ bool CallPrivate::getAudioMuted () const {
shared_ptr<RealTimeTextChatRoom> CallPrivate::getChatRoom () {
L_Q();
if (!chatRoom && (q->getState() != CallSession::State::End) && (q->getState() != CallSession::State::Released)) {
ChatRoomId chatRoomId(q->getRemoteAddress(), q->getLocalAddress());
RealTimeTextChatRoom *rttcr = new RealTimeTextChatRoom(q->getCore(), chatRoomId);
chatRoom.reset(rttcr);
rttcr->getPrivate()->setCall(q->getSharedFromThis());
chatRoom = static_pointer_cast<RealTimeTextChatRoom>(q->getCore()->getOrCreateBasicChatRoom(q->getRemoteAddress(), true));
chatRoom->getPrivate()->setCall(q->getSharedFromThis());
}
return chatRoom;
}
@ -124,7 +122,6 @@ shared_ptr<Call> CallPrivate::startReferredCall (const MediaSessionParams *param
L_GET_PRIVATE(getActiveSession())->setReferPending(false);
LinphoneCallParams *lcp = L_GET_C_BACK_PTR(&msp);
LinphoneCall *newCall = linphone_core_invite_with_params(q->getCore()->getCCore(), q->getReferTo().c_str(), lcp);
linphone_call_params_unref(lcp);
if (newCall) {
getActiveSession()->getPrivate()->setTransferTarget(L_GET_PRIVATE_FROM_C_OBJECT(newCall)->getActiveSession());
L_GET_PRIVATE_FROM_C_OBJECT(newCall)->getActiveSession()->getPrivate()->notifyReferState();
@ -418,6 +415,7 @@ void CallPrivate::onFirstVideoFrameDecoded (const shared_ptr<CallSession> &sessi
nextVideoFrameDecoded._func = nullptr;
nextVideoFrameDecoded._user_data = nullptr;
}
linphone_call_notify_next_video_frame_decoded(L_GET_C_BACK_PTR(q));
}
void CallPrivate::onResetFirstVideoFrameDecoded (const shared_ptr<CallSession> &session) {
@ -496,6 +494,11 @@ void CallPrivate::onTmmbrReceived (const shared_ptr<CallSession> &session, int s
linphone_call_notify_tmmbr_received(L_GET_C_BACK_PTR(q), streamIndex, tmmbr);
}
void CallPrivate::onSnapshotTaken(const shared_ptr<CallSession> &session, const char *file_path) {
L_Q();
linphone_call_notify_snapshot_taken(L_GET_C_BACK_PTR(q), file_path);
}
// =============================================================================
Call::Call (CallPrivate &p, shared_ptr<Core> core) : Object(p), CoreAccessor(core) {

View file

@ -26,8 +26,8 @@
#include "chat/chat-room/chat-room-id.h"
#include "chat/modifier/file-transfer-chat-message-modifier.h"
#include "chat/notification/imdn.h"
#include "content/content-type.h"
#include "content/content.h"
#include "content/content-type.h"
#include "content/file-content.h"
#include "content/file-transfer-content.h"
#include "db/main-db.h"
@ -44,6 +44,7 @@ class ChatMessagePrivate : public ObjectPrivate {
friend class CpimChatMessageModifier;
friend class EncryptionChatMessageModifier;
friend class MultipartChatMessageModifier;
friend class NotificationMessagePrivate;
public:
enum Step {
@ -59,9 +60,8 @@ public:
void setDirection (ChatMessage::Direction dir);
std::list<ParticipantImdnState> getParticipantsByImdnState (MainDb::ParticipantStateRetrievalFunc func) const;
void setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState, time_t stateChangeTime);
void setState (ChatMessage::State newState, bool force = false);
virtual void setState (ChatMessage::State newState, bool force = false);
void setTime (time_t time);
@ -99,6 +99,13 @@ public:
SalOp *getSalOp () const;
void setSalOp (SalOp *op);
bool getDisplayNotificationRequired () const { return displayNotificationRequired; }
bool getNegativeDeliveryNotificationRequired () const { return negativeDeliveryNotificationRequired; }
bool getPositiveDeliveryNotificationRequired () const { return positiveDeliveryNotificationRequired; }
virtual void setDisplayNotificationRequired (bool value) { displayNotificationRequired = value; }
virtual void setNegativeDeliveryNotificationRequired (bool value) { negativeDeliveryNotificationRequired = value; }
virtual void setPositiveDeliveryNotificationRequired (bool value) { positiveDeliveryNotificationRequired = value; }
SalCustomHeader *getSalCustomHeaders () const;
void setSalCustomHeaders (SalCustomHeader *headers);
@ -146,8 +153,6 @@ public:
bool downloadFile ();
void sendImdn (Imdn::Type imdnType, LinphoneReason reason);
void notifyReceiving ();
LinphoneReason receive ();
void send ();
@ -156,11 +161,21 @@ public:
void updateInDb ();
private:
ChatMessagePrivate(const std::shared_ptr<AbstractChatRoom> &cr, ChatMessage::Direction dir);
static bool validStateTransition (ChatMessage::State currentState, ChatMessage::State newState);
public:
mutable MainDbChatMessageKey dbKey;
protected:
bool displayNotificationRequired = true;
bool negativeDeliveryNotificationRequired = true;
bool positiveDeliveryNotificationRequired = true;
bool toBeStored = true;
std::string contentEncoding;
private:
// TODO: Clean attributes.
time_t time = ::ms_time(0); // TODO: Change me in all files.
std::string imdnId;
@ -189,10 +204,6 @@ private:
// TODO: Remove my comment. VARIABLES OK.
// Do not expose.
public:
mutable MainDbChatMessageKey dbKey;
private:
std::weak_ptr<AbstractChatRoom> chatRoom;
ChatRoomId chatRoomId;
IdentityAddress fromAddress;
@ -204,7 +215,6 @@ private:
std::list<Content* > contents;
bool encryptionPrevented = false;
bool toBeStored = true;
mutable bool contentsNotLoadedFromDatabase = false;
L_DECLARE_PUBLIC(ChatMessage);
};

View file

@ -33,17 +33,15 @@
#include "chat/chat-room/real-time-text-chat-room.h"
#include "chat/modifier/cpim-chat-message-modifier.h"
#include "chat/modifier/encryption-chat-message-modifier.h"
#include "chat/modifier/file-transfer-chat-message-modifier.h"
#include "chat/modifier/multipart-chat-message-modifier.h"
#include "chat/notification/imdn.h"
#include "conference/participant.h"
#include "conference/participant-imdn-state.h"
#include "content/file-content.h"
#include "content/content-disposition.h"
#include "content/header/header-param.h"
#include "content/content.h"
#include "core/core.h"
#include "core/core-p.h"
#include "logger/logger.h"
#include "chat/notification/imdn.h"
#include "sip-tools/sip-headers.h"
#include "ortp/b64.h"
@ -73,25 +71,6 @@ void ChatMessagePrivate::setIsReadOnly (bool readOnly) {
isReadOnly = readOnly;
}
list<ParticipantImdnState> ChatMessagePrivate::getParticipantsByImdnState (MainDb::ParticipantStateRetrievalFunc func) const {
L_Q();
list<ParticipantImdnState> result;
if (!(q->getChatRoom()->getCapabilities() & AbstractChatRoom::Capabilities::Conference) || !dbKey.isValid())
return result;
unique_ptr<MainDb> &mainDb = q->getChatRoom()->getCore()->getPrivate()->mainDb;
shared_ptr<EventLog> eventLog = mainDb->getEventFromKey(dbKey);
list<MainDb::ParticipantState> dbResults = func(eventLog);
for (const auto &dbResult : dbResults) {
auto participant = q->getChatRoom()->findParticipant(dbResult.address);
if (participant)
result.emplace_back(participant, dbResult.state, dbResult.timestamp);
}
return result;
}
void ChatMessagePrivate::setParticipantState (const IdentityAddress &participantAddress, ChatMessage::State newState, time_t stateChangeTime) {
L_Q();
@ -181,8 +160,9 @@ void ChatMessagePrivate::setState (ChatMessage::State newState, bool force) {
if (state == ChatMessage::State::FileTransferDone && !hasFileTransferContent()) {
// We wait until the file has been downloaded to send the displayed IMDN
q->sendDisplayNotification();
setState(ChatMessage::State::Displayed);
bool doNotStoreInDb = static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDisplayNotification(q->getSharedFromThis());
// Force the state so it is stored directly in DB, but when the IMDN has successfully been delivered
setState(ChatMessage::State::Displayed, doNotStoreInDb);
} else {
updateInDb();
}
@ -456,25 +436,6 @@ void ChatMessagePrivate::setChatRoom (const shared_ptr<AbstractChatRoom> &cr) {
// -----------------------------------------------------------------------------
void ChatMessagePrivate::sendImdn (Imdn::Type imdnType, LinphoneReason reason) {
L_Q();
shared_ptr<ChatMessage> msg = q->getChatRoom()->createChatMessage();
Content *content = new Content();
content->setContentType(ContentType::Imdn);
content->setBody(Imdn::createXml(imdnId, time, imdnType, reason));
msg->addContent(content);
if (reason != LinphoneReasonNone)
msg->getPrivate()->setEncryptionPrevented(true);
msg->setToBeStored(false);
msg->getPrivate()->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
msg->getPrivate()->send();
}
static void forceUtf8Content (Content &content) {
// TODO: Deal with other content type in the future.
ContentType contentType = content.getContentType();
@ -516,6 +477,11 @@ void ChatMessagePrivate::notifyReceiving () {
_linphone_chat_room_notify_chat_message_should_be_stored(chatRoom, L_GET_C_BACK_PTR(q->getSharedFromThis()));
if (toBeStored)
storeInDb();
} else {
// For compatibility, when CPIM is not used
positiveDeliveryNotificationRequired = false;
negativeDeliveryNotificationRequired = false;
displayNotificationRequired = false;
}
shared_ptr<ConferenceChatMessageEvent> event = make_shared<ConferenceChatMessageEvent>(
::time(nullptr), q->getSharedFromThis()
@ -524,9 +490,8 @@ void ChatMessagePrivate::notifyReceiving () {
// Legacy
q->getChatRoom()->getPrivate()->notifyChatMessageReceived(q->getSharedFromThis());
if ((getContentType() != ContentType::Imdn) && (getContentType() != ContentType::ImIsComposing)) {
q->sendDeliveryNotification(LinphoneReasonNone);
}
if (getPositiveDeliveryNotificationRequired())
static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDeliveryNotification(q->getSharedFromThis());
}
LinphoneReason ChatMessagePrivate::receive () {
@ -550,7 +515,12 @@ LinphoneReason ChatMessagePrivate::receive () {
/* Unable to decrypt message */
chatRoom->getPrivate()->notifyUndecryptableChatMessageReceived(q->getSharedFromThis());
reason = linphone_error_code_to_reason(errorCode);
q->sendDeliveryNotification(reason);
if (getNegativeDeliveryNotificationRequired()) {
static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDeliveryErrorNotification(
q->getSharedFromThis(),
reason
);
}
return reason;
} else if (result == ChatMessageModifier::Result::Suspended) {
currentRecvStep |= ChatMessagePrivate::Step::Encryption;
@ -634,7 +604,12 @@ LinphoneReason ChatMessagePrivate::receive () {
if (errorCode > 0) {
reason = linphone_error_code_to_reason(errorCode);
q->sendDeliveryNotification(reason);
if (getNegativeDeliveryNotificationRequired()) {
static_cast<ChatRoomPrivate *>(q->getChatRoom()->getPrivate())->sendDeliveryErrorNotification(
q->getSharedFromThis(),
reason
);
}
return reason;
}
@ -705,11 +680,11 @@ void ChatMessagePrivate::send () {
core->getCCore(), op, peer, getSalCustomHeaders(),
!!lp_config_get_int(core->getCCore()->config, "sip", "chat_msg_with_contact", 0)
);
op->set_user_pointer(q); /* If out of call, directly store msg */
op->setUserPointer(q); /* If out of call, directly store msg */
linphone_address_unref(peer);
}
op->set_from(q->getFromAddress().asString().c_str());
op->set_to(q->getToAddress().asString().c_str());
op->setFrom(q->getFromAddress().asString().c_str());
op->setTo(q->getToAddress().asString().c_str());
// ---------------------------------------
// Start of message modification
@ -746,7 +721,7 @@ void ChatMessagePrivate::send () {
EncryptionChatMessageModifier ecmm;
ChatMessageModifier::Result result = ecmm.encode(q->getSharedFromThis(), errorCode);
if (result == ChatMessageModifier::Result::Error) {
sal_error_info_set((SalErrorInfo *)op->get_error_info(), SalReasonNotAcceptable, "SIP", errorCode, "Unable to encrypt IM", nullptr);
sal_error_info_set((SalErrorInfo *)op->getErrorInfo(), SalReasonNotAcceptable, "SIP", errorCode, "Unable to encrypt IM", nullptr);
setState(ChatMessage::State::NotDelivered);
return;
} else if (result == ChatMessageModifier::Result::Suspended) {
@ -773,13 +748,18 @@ void ChatMessagePrivate::send () {
auto msgOp = dynamic_cast<SalMessageOpInterface *>(op);
if (!externalBodyUrl.empty()) {
char *content_type = ms_strdup_printf("message/external-body;access-type=URL;URL=\"%s\"", externalBodyUrl.c_str());
msgOp->send_message(content_type, NULL);
ms_free(content_type);
} else if (internalContent.getContentType().isValid()) {
msgOp->send_message(internalContent.getContentType().asString().c_str(), internalContent.getBodyAsUtf8String().c_str());
Content content;
ContentType contentType(ContentType::ExternalBody);
contentType.addParameter("access-type", "URL");
contentType.addParameter("URL", "\"" + externalBodyUrl + "\"");
content.setContentType(contentType);
msgOp->sendMessage(content);
} else {
msgOp->send_message(ContentType::PlainText.asString().c_str(), internalContent.getBodyAsUtf8String().c_str());
if (!internalContent.getContentType().isValid())
internalContent.setContentType(ContentType::PlainText);
if (!contentEncoding.empty())
internalContent.setContentEncoding(contentEncoding);
msgOp->sendMessage(internalContent);
}
// Restore FileContents and remove FileTransferContents
@ -803,7 +783,7 @@ void ChatMessagePrivate::send () {
currentSendStep = ChatMessagePrivate::Step::None;
if (imdnId.empty())
setImdnMessageId(op->get_call_id()); /* must be known at that time */
setImdnMessageId(op->getCallId()); /* must be known at that time */
if (lcall && linphone_call_get_op(lcall) == op) {
/* In this case, chat delivery status is not notified, so unrefing chat message right now */
@ -892,17 +872,25 @@ bool ChatMessagePrivate::validStateTransition (ChatMessage::State currentState,
// -----------------------------------------------------------------------------
ChatMessage::ChatMessage (const shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction) :
Object(*new ChatMessagePrivate(chatRoom,direction)), CoreAccessor(chatRoom->getCore()) {
Object(*new ChatMessagePrivate(chatRoom, direction)), CoreAccessor(chatRoom->getCore()) {
}
ChatMessage::ChatMessage (ChatMessagePrivate &p) : Object(p), CoreAccessor(p.getPublic()->getChatRoom()->getCore()) {
}
ChatMessage::~ChatMessage () {
L_D();
for (Content *content : d->contents)
for (Content *content : d->contents) {
if (content->isFileTransfer()) {
FileTransferContent *fileTransferContent = static_cast<FileTransferContent *>(content);
delete fileTransferContent->getFileContent();
}
delete content;
}
if (d->salOp) {
d->salOp->set_user_pointer(nullptr);
d->salOp->setUserPointer(nullptr);
d->salOp->unref();
}
if (d->salCustomHeaders)
@ -1010,25 +998,24 @@ void ChatMessage::setToBeStored (bool value) {
// -----------------------------------------------------------------------------
list<ParticipantImdnState> ChatMessage::getParticipantsThatHaveDisplayed () const {
list<ParticipantImdnState> ChatMessage::getParticipantsByImdnState (ChatMessage::State state) const {
L_D();
unique_ptr<MainDb> &mainDb = getChatRoom()->getCore()->getPrivate()->mainDb;
auto func = bind(&MainDb::getChatMessageParticipantsThatHaveDisplayed, mainDb.get(), std::placeholders::_1);
return d->getParticipantsByImdnState(func);
}
list<ParticipantImdnState> ChatMessage::getParticipantsThatHaveNotReceived () const {
L_D();
unique_ptr<MainDb> &mainDb = getChatRoom()->getCore()->getPrivate()->mainDb;
auto func = bind(&MainDb::getChatMessageParticipantsThatHaveNotReceived, mainDb.get(), std::placeholders::_1);
return d->getParticipantsByImdnState(func);
}
list<ParticipantImdnState> result;
if (!(getChatRoom()->getCapabilities() & AbstractChatRoom::Capabilities::Conference) || !d->dbKey.isValid())
return result;
list<ParticipantImdnState> ChatMessage::getParticipantsThatHaveReceived () const {
L_D();
unique_ptr<MainDb> &mainDb = getChatRoom()->getCore()->getPrivate()->mainDb;
auto func = bind(&MainDb::getChatMessageParticipantsThatHaveReceived, mainDb.get(), std::placeholders::_1);
return d->getParticipantsByImdnState(func);
shared_ptr<EventLog> eventLog = mainDb->getEventFromKey(d->dbKey);
list<MainDb::ParticipantState> dbResults = mainDb->getChatMessageParticipantsByImdnState(eventLog, state);
for (const auto &dbResult : dbResults) {
auto sender = getChatRoom()->findParticipant(getFromAddress());
auto participant = getChatRoom()->findParticipant(dbResult.address);
if (participant && (participant != sender))
result.emplace_back(participant, dbResult.state, dbResult.timestamp);
}
return result;
}
// -----------------------------------------------------------------------------
@ -1110,22 +1097,6 @@ void ChatMessage::send () {
getChatRoom()->getPrivate()->sendChatMessage(getSharedFromThis());
}
void ChatMessage::sendDeliveryNotification (LinphoneReason reason) {
L_D();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_delivered(policy))
d->sendImdn(Imdn::Type::Delivery, reason);
}
void ChatMessage::sendDisplayNotification () {
L_D();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_displayed(policy))
d->sendImdn(Imdn::Type::Display, LinphoneReasonNone);
}
bool ChatMessage::downloadFile(FileTransferContent *fileTransferContent) {
L_D();
return d->fileTransferChatMessageModifier.downloadFile(getSharedFromThis(), fileTransferContent);
@ -1171,22 +1142,16 @@ int ChatMessage::putCharacter (uint32_t character) {
if (character == newLine || character == crlf || character == lf) {
shared_ptr<Core> core = getCore();
if (lp_config_get_int(core->getCCore()->config, "misc", "store_rtt_messages", 1) == 1) {
// TODO: History.
lDebug() << "New line sent, forge a message with content " << d->rttMessage.c_str();
d->setTime(ms_time(0));
lInfo() << "New line sent, forge a message with content " << d->rttMessage;
d->state = State::Displayed;
// d->direction = Direction::Outgoing;
// setFromAddress(Address(
// linphone_address_as_string(linphone_address_new(linphone_core_get_identity(core->getCCore())))
// ));
// linphone_chat_message_store(L_GET_C_BACK_PTR(this));
d->setText(d->rttMessage);
d->storeInDb();
d->rttMessage = "";
}
} else {
char *value = LinphonePrivate::Utils::utf8ToChar(character);
d->rttMessage = d->rttMessage + string(value);
lDebug() << "Sent RTT character: " << value << "(" << (unsigned long)character <<
"), pending text is " << d->rttMessage.c_str();
d->rttMessage += string(value);
lDebug() << "Sent RTT character: " << value << "(" << (unsigned long)character << "), pending text is " << d->rttMessage;
delete[] value;
}

View file

@ -50,6 +50,7 @@ class LINPHONE_PUBLIC ChatMessage : public Object, public CoreAccessor {
friend class CpimChatMessageModifier;
friend class FileTransferChatMessageModifier;
friend class Imdn;
friend class ImdnMessagePrivate;
friend class MainDb;
friend class MainDbPrivate;
friend class RealTimeTextChatRoomPrivate;
@ -61,13 +62,11 @@ public:
L_DECLARE_ENUM(State, L_ENUM_VALUES_CHAT_MESSAGE_STATE);
L_DECLARE_ENUM(Direction, L_ENUM_VALUES_CHAT_MESSAGE_DIRECTION);
~ChatMessage ();
virtual ~ChatMessage ();
// ----- TODO: Remove me.
void cancelFileTransfer ();
int putCharacter (uint32_t character);
void sendDeliveryNotification (LinphoneReason reason);
void sendDisplayNotification ();
void setIsSecured (bool isSecured);
// ----- TODO: Remove me.
@ -93,11 +92,9 @@ public:
bool isReadOnly () const;
bool getToBeStored () const;
void setToBeStored (bool value);
virtual void setToBeStored (bool value);
std::list<ParticipantImdnState> getParticipantsThatHaveDisplayed () const;
std::list<ParticipantImdnState> getParticipantsThatHaveReceived () const;
std::list<ParticipantImdnState> getParticipantsThatHaveNotReceived () const;
std::list<ParticipantImdnState> getParticipantsByImdnState (State state) const;
const std::list<Content *> &getContents () const;
void addContent (Content *content);
@ -114,6 +111,9 @@ public:
bool downloadFile (FileTransferContent *content);
bool isFileTransferInProgress();
protected:
explicit ChatMessage (ChatMessagePrivate &p);
private:
ChatMessage (const std::shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction);

View file

@ -1,5 +1,5 @@
/*
* search-result-p.h
* imdn-message-p.h
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
@ -17,26 +17,31 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_SEARCH_RESULT_P_H_
#define _L_SEARCH_RESULT_P_H_
#ifndef _L_IMDN_MESSAGE_P_H_
#define _L_IMDN_MESSAGE_P_H_
#include "search-result.h"
#include "object/clonable-object-p.h"
#include "chat/chat-message/imdn-message.h"
#include "chat/chat-message/notification-message-p.h"
#include "linphone/types.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class SearchResultPrivate : public ClonableObjectPrivate {
private:
const LinphoneFriend *mFriend;
const LinphoneAddress *mAddress;
unsigned int mWeight;
class ImdnMessagePrivate : public NotificationMessagePrivate {
public:
const ImdnMessage::Context &getContext () { return context; }
L_DECLARE_PUBLIC(SearchResult);
private:
ImdnMessagePrivate (const ImdnMessage::Context &context)
: NotificationMessagePrivate(context.chatRoom, ChatMessage::Direction::Outgoing), context(context) {}
void setState (ChatMessage::State newState, bool force = false) override;
ImdnMessage::Context context;
L_DECLARE_PUBLIC(ImdnMessage);
};
LINPHONE_END_NAMESPACE
#endif //_L_SEARCH_RESULT_P_H_
#endif // ifndef _L_IMDN_MESSAGE_P_H_

View file

@ -0,0 +1,93 @@
/*
* imdn-message.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 "chat/chat-message/imdn-message-p.h"
#include "chat/chat-room/chat-room-p.h"
#include "content/content-disposition.h"
#include "logger/logger.h"
#include "sip-tools/sip-headers.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
void ImdnMessagePrivate::setState (ChatMessage::State newState, bool force) {
L_Q();
if (newState == ChatMessage::State::Delivered) {
for (const auto &message : context.deliveredMessages)
message->getPrivate()->updateInDb();
for (const auto &message : context.displayedMessages)
message->getPrivate()->updateInDb();
static_pointer_cast<ChatRoom>(context.chatRoom)->getPrivate()->getImdnHandler()->onImdnMessageDelivered(q->getSharedFromThis());
} else if (newState == ChatMessage::State::NotDelivered) {
// TODO: Maybe we should retry sending the IMDN message if we get an error here
}
}
// -----------------------------------------------------------------------------
ImdnMessage::ImdnMessage (
const shared_ptr<AbstractChatRoom> &chatRoom,
const list<shared_ptr<ChatMessage>> &deliveredMessages,
const list<shared_ptr<ChatMessage>> &displayedMessages
) : ImdnMessage(Context(chatRoom, deliveredMessages, displayedMessages)) {}
ImdnMessage::ImdnMessage (
const shared_ptr<AbstractChatRoom> &chatRoom,
const list<Imdn::MessageReason> &nonDeliveredMessages
) : ImdnMessage(Context(chatRoom, nonDeliveredMessages)) {}
ImdnMessage::ImdnMessage (const std::shared_ptr<ImdnMessage> &message) : ImdnMessage(message->getPrivate()->context) {}
ImdnMessage::ImdnMessage (const Context &context) : NotificationMessage(*new ImdnMessagePrivate(context)) {
L_D();
for (const auto &message : d->context.deliveredMessages) {
Content *content = new Content();
content->setContentDisposition(ContentDisposition::Notification);
content->setContentType(ContentType::Imdn);
content->setBody(Imdn::createXml(message->getImdnMessageId(), message->getTime(), Imdn::Type::Delivery, LinphoneReasonNone));
addContent(content);
}
for (const auto &message : d->context.displayedMessages) {
Content *content = new Content();
content->setContentDisposition(ContentDisposition::Notification);
content->setContentType(ContentType::Imdn);
content->setBody(Imdn::createXml(message->getImdnMessageId(), message->getTime(), Imdn::Type::Display, LinphoneReasonNone));
addContent(content);
}
for (const auto &mr : d->context.nonDeliveredMessages) {
Content *content = new Content();
content->setContentDisposition(ContentDisposition::Notification);
content->setContentType(ContentType::Imdn);
content->setBody(Imdn::createXml(mr.message->getImdnMessageId(), mr.message->getTime(), Imdn::Type::Delivery, mr.reason));
addContent(content);
}
d->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
if (!d->context.nonDeliveredMessages.empty())
d->setEncryptionPrevented(true);
}
LINPHONE_END_NAMESPACE

View file

@ -0,0 +1,77 @@
/*
* imdn-message.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_IMDN_MESSAGE_H_
#define _L_IMDN_MESSAGE_H_
#include "chat/chat-message/notification-message.h"
#include "chat/notification/imdn.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ImdnMessagePrivate;
class LINPHONE_PUBLIC ImdnMessage : public NotificationMessage {
public:
friend class ChatRoomPrivate;
friend class Imdn;
L_OVERRIDE_SHARED_FROM_THIS(ImdnMessage);
virtual ~ImdnMessage () = default;
private:
struct Context {
Context (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const std::list<std::shared_ptr<ChatMessage>> &deliveredMessages,
const std::list<std::shared_ptr<ChatMessage>> &displayedMessages
) : chatRoom(chatRoom), deliveredMessages(deliveredMessages), displayedMessages(displayedMessages) {}
Context (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const std::list<Imdn::MessageReason> &nonDeliveredMessages
) : chatRoom(chatRoom), nonDeliveredMessages(nonDeliveredMessages) {}
std::shared_ptr<AbstractChatRoom> chatRoom;
std::list<std::shared_ptr<ChatMessage>> deliveredMessages;
std::list<std::shared_ptr<ChatMessage>> displayedMessages;
std::list<Imdn::MessageReason> nonDeliveredMessages;
};
ImdnMessage (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const std::list<std::shared_ptr<ChatMessage>> &deliveredMessages,
const std::list<std::shared_ptr<ChatMessage>> &displayedMessages
);
ImdnMessage (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const std::list<Imdn::MessageReason> &nonDeliveredMessages
);
ImdnMessage (const std::shared_ptr<ImdnMessage> &message);
ImdnMessage (const Context &context);
L_DECLARE_PRIVATE(ImdnMessage);
L_DISABLE_COPY(ImdnMessage);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_IMDN_MESSAGE_H_

View file

@ -0,0 +1,46 @@
/*
* is-composing-message.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 "chat/chat-message/notification-message-p.h"
#include "chat/chat-message/is-composing-message.h"
#include "sip-tools/sip-headers.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
IsComposingMessage::IsComposingMessage (
const shared_ptr<AbstractChatRoom> &chatRoom,
IsComposing &isComposingHandler,
bool isComposing
) : NotificationMessage(*new NotificationMessagePrivate(chatRoom, ChatMessage::Direction::Outgoing)) {
L_D();
Content *content = new Content();
content->setContentType(ContentType::ImIsComposing);
content->setBody(isComposingHandler.createXml(isComposing));
addContent(content);
d->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
d->addSalCustomHeader("Expires", "0");
}
LINPHONE_END_NAMESPACE

View file

@ -0,0 +1,51 @@
/*
* is-composing-message.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_IS_COMPOSING_MESSAGE_H_
#define _L_IS_COMPOSING_MESSAGE_H_
#include "chat/chat-message/notification-message.h"
#include "chat/notification/is-composing.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class LINPHONE_PUBLIC IsComposingMessage : public NotificationMessage {
public:
friend class ChatRoomPrivate;
L_OVERRIDE_SHARED_FROM_THIS(IsComposingMessage);
virtual ~IsComposingMessage () = default;
private:
IsComposingMessage (
const std::shared_ptr<AbstractChatRoom> &chatRoom,
IsComposing &isComposingHandler,
bool isComposing
);
L_DECLARE_PRIVATE(NotificationMessage);
L_DISABLE_COPY(IsComposingMessage);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_IS_COMPOSING_MESSAGE_H_

View file

@ -0,0 +1,50 @@
/*
* notification-message-p.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_NOTIFICATION_MESSAGE_P_H_
#define _L_NOTIFICATION_MESSAGE_P_H_
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-message/notification-message.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class NotificationMessagePrivate : public ChatMessagePrivate {
friend class ImdnMessage;
friend class IsComposingMessage;
protected:
NotificationMessagePrivate(const std::shared_ptr<AbstractChatRoom> &cr, ChatMessage::Direction dir)
: ChatMessagePrivate(cr, dir) {}
void setState (ChatMessage::State newState, bool force = false) override {};
private:
void setDisplayNotificationRequired (bool value) override {}
void setNegativeDeliveryNotificationRequired (bool value) override {}
void setPositiveDeliveryNotificationRequired (bool value) override {}
L_DECLARE_PUBLIC(NotificationMessage);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_NOTIFICATION_MESSAGE_P_H_

View file

@ -0,0 +1,46 @@
/*
* notification-message.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 "chat/chat-message/notification-message-p.h"
// =============================================================================
using namespace std;
LINPHONE_BEGIN_NAMESPACE
// -----------------------------------------------------------------------------
NotificationMessage::NotificationMessage (const shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction) :
NotificationMessage(*new NotificationMessagePrivate(chatRoom, direction)) {
}
NotificationMessage::NotificationMessage (NotificationMessagePrivate &p) : ChatMessage(p) {
L_D();
d->displayNotificationRequired = false;
d->negativeDeliveryNotificationRequired = false;
d->positiveDeliveryNotificationRequired = false;
d->toBeStored = false;
d->contentEncoding = "deflate";
}
void NotificationMessage::setToBeStored (bool value) {
}
LINPHONE_END_NAMESPACE

View file

@ -0,0 +1,53 @@
/*
* notification-message.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_NOTIFICATION_MESSAGE_H_
#define _L_NOTIFICATION_MESSAGE_H_
#include "chat/chat-message/chat-message.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class NotificationMessagePrivate;
class LINPHONE_PUBLIC NotificationMessage : public ChatMessage {
public:
friend class ChatRoomPrivate;
L_OVERRIDE_SHARED_FROM_THIS(NotificationMessage);
virtual ~NotificationMessage () = default;
void setToBeStored (bool value) override;
protected:
explicit NotificationMessage (NotificationMessagePrivate &p);
private:
NotificationMessage (const std::shared_ptr<AbstractChatRoom> &chatRoom, ChatMessage::Direction direction);
L_DECLARE_PRIVATE(NotificationMessage);
L_DISABLE_COPY(NotificationMessage);
};
LINPHONE_END_NAMESPACE
#endif // ifndef _L_NOTIFICATION_MESSAGE_H_

View file

@ -47,6 +47,8 @@ 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 notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
virtual void notifyUndecryptableChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) = 0;

View file

@ -25,12 +25,16 @@
#include "abstract-chat-room-p.h"
#include "chat-room-id.h"
#include "chat-room.h"
#include "chat/notification/imdn.h"
#include "chat/notification/is-composing.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ImdnMessage;
class IsComposingMessage;
class ChatRoomPrivate : public AbstractChatRoomPrivate, public IsComposingListener {
public:
inline void setProxyChatRoom (AbstractChatRoom *value) { proxyChatRoom = value; }
@ -54,8 +58,20 @@ public:
void removeTransientEvent (const std::shared_ptr<EventLog> &eventLog) override;
std::shared_ptr<ChatMessage> createChatMessage (ChatMessage::Direction direction);
std::shared_ptr<ImdnMessage> createImdnMessage (
const std::list<std::shared_ptr<ChatMessage>> &deliveredMessages,
const std::list<std::shared_ptr<ChatMessage>> &displayedMessages
);
std::shared_ptr<ImdnMessage> createImdnMessage (const std::list<Imdn::MessageReason> &nonDeliveredMessages);
std::shared_ptr<ImdnMessage> createImdnMessage (const std::shared_ptr<ImdnMessage> &message);
std::shared_ptr<IsComposingMessage> createIsComposingMessage ();
std::list<std::shared_ptr<ChatMessage>> findChatMessages (const std::string &messageId) const;
void sendDeliveryErrorNotification (const std::shared_ptr<ChatMessage> &message, LinphoneReason reason);
void sendDeliveryNotification (const std::shared_ptr<ChatMessage> &message);
void sendDeliveryNotifications () override;
bool sendDisplayNotification (const std::shared_ptr<ChatMessage> &message);
void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override;
void notifyIsComposingReceived (const Address &remoteAddress, bool isComposing);
void notifyStateChanged ();
@ -69,6 +85,8 @@ public:
void onIsComposingStateChanged (bool isComposing) override;
void onIsRemoteComposingStateChanged (const Address &remoteAddress, bool isComposing) override;
Imdn *getImdnHandler () const { return imdnHandler.get(); }
LinphoneChatRoom *getCChatRoom () const;
std::list<IdentityAddress> remoteIsComposing;
@ -84,6 +102,7 @@ private:
time_t creationTime = std::time(nullptr);
time_t lastUpdateTime = std::time(nullptr);
std::unique_ptr<Imdn> imdnHandler;
std::unique_ptr<IsComposing> isComposingHandler;
bool isComposing = false;

View file

@ -23,9 +23,11 @@
#include "c-wrapper/c-wrapper.h"
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-message/imdn-message.h"
#include "chat/chat-message/is-composing-message.h"
#include "chat/chat-message/notification-message-p.h"
#include "chat/chat-room/chat-room-p.h"
#include "core/core-p.h"
#include "sip-tools/sip-headers.h"
#include "logger/logger.h"
// =============================================================================
@ -76,21 +78,8 @@ void ChatRoomPrivate::sendIsComposingNotification () {
if (!linphone_im_notif_policy_get_send_is_composing(policy))
return;
string payload = isComposingHandler->marshal(isComposing);
if (payload.empty())
return;
Content *content = new Content();
content->setContentType(ContentType::ImIsComposing);
content->setBody(payload);
shared_ptr<ChatMessage> chatMessage = createChatMessage(ChatMessage::Direction::Outgoing);
chatMessage->setToBeStored(false);
chatMessage->addContent(content);
chatMessage->getPrivate()->addSalCustomHeader(PriorityHeader::HeaderName, PriorityHeader::NonUrgent);
chatMessage->getPrivate()->addSalCustomHeader("Expires", "0");
chatMessage->getPrivate()->send();
auto isComposingMsg = createIsComposingMessage();
isComposingMsg->getPrivate()->send();
}
// -----------------------------------------------------------------------------
@ -121,6 +110,28 @@ shared_ptr<ChatMessage> ChatRoomPrivate::createChatMessage (ChatMessage::Directi
return shared_ptr<ChatMessage>(new ChatMessage(q->getSharedFromThis(), direction));
}
shared_ptr<ImdnMessage> ChatRoomPrivate::createImdnMessage (
const list<shared_ptr<ChatMessage>> &deliveredMessages,
const list<shared_ptr<ChatMessage>> &displayedMessages
) {
L_Q();
return shared_ptr<ImdnMessage>(new ImdnMessage(q->getSharedFromThis(), deliveredMessages, displayedMessages));
}
shared_ptr<ImdnMessage> ChatRoomPrivate::createImdnMessage (const list<Imdn::MessageReason> &nonDeliveredMessages) {
L_Q();
return shared_ptr<ImdnMessage>(new ImdnMessage(q->getSharedFromThis(), nonDeliveredMessages));
}
shared_ptr<ImdnMessage> ChatRoomPrivate::createImdnMessage (const shared_ptr<ImdnMessage> &message) {
return shared_ptr<ImdnMessage>(new ImdnMessage(message));
}
shared_ptr<IsComposingMessage> ChatRoomPrivate::createIsComposingMessage () {
L_Q();
return shared_ptr<IsComposingMessage>(new IsComposingMessage(q->getSharedFromThis(), *isComposingHandler.get(), isComposing));
}
list<shared_ptr<ChatMessage>> ChatRoomPrivate::findChatMessages (const string &messageId) const {
L_Q();
return q->getCore()->getPrivate()->mainDb->findChatMessages(q->getChatRoomId(), messageId);
@ -128,6 +139,42 @@ list<shared_ptr<ChatMessage>> ChatRoomPrivate::findChatMessages (const string &m
// -----------------------------------------------------------------------------
void ChatRoomPrivate::sendDeliveryErrorNotification (const shared_ptr<ChatMessage> &message, LinphoneReason reason) {
L_Q();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_delivered(policy))
imdnHandler->notifyDeliveryError(message, reason);
}
void ChatRoomPrivate::sendDeliveryNotification (const shared_ptr<ChatMessage> &message) {
L_Q();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_delivered(policy))
imdnHandler->notifyDelivery(message);
}
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 messages = q->getCore()->getPrivate()->mainDb->findChatMessagesToBeNotifiedAsDelivered(q->getChatRoomId());
for (const auto message : messages)
imdnHandler->notifyDelivery(message);
}
}
bool ChatRoomPrivate::sendDisplayNotification (const shared_ptr<ChatMessage> &message) {
L_Q();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_displayed(policy)) {
imdnHandler->notifyDisplay(message);
return true;
}
return false;
}
// -----------------------------------------------------------------------------
void ChatRoomPrivate::notifyChatMessageReceived (const shared_ptr<ChatMessage> &chatMessage) {
L_Q();
LinphoneChatRoom *cr = getCChatRoom();
@ -188,7 +235,7 @@ LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessag
LinphoneCore *cCore = core->getCCore();
msg = createChatMessage(
IdentityAddress(op->get_from()) == q->getLocalAddress()
IdentityAddress(op->getFrom()) == q->getLocalAddress()
? ChatMessage::Direction::Outgoing
: ChatMessage::Direction::Incoming
);
@ -205,35 +252,30 @@ LinphoneReason ChatRoomPrivate::onSipMessageReceived (SalOp *op, const SalMessag
msg->setInternalContent(content);
msg->getPrivate()->setTime(message->time);
msg->getPrivate()->setImdnMessageId(op->get_call_id());
msg->getPrivate()->setImdnMessageId(op->getCallId());
const SalCustomHeader *ch = op->get_recv_custom_header();
const SalCustomHeader *ch = op->getRecvCustomHeaders();
if (ch)
msg->getPrivate()->setSalCustomHeaders(sal_custom_header_clone(ch));
reason = msg->getPrivate()->receive();
if (reason == LinphoneReasonNotAcceptable || reason == LinphoneReasonUnknown) {
/* Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt */
reason = LinphoneReasonNone;
goto end;
// Return LinphoneReasonNone to avoid flexisip resending us a message we can't decrypt
return LinphoneReasonNone;
}
if (msg->getPrivate()->getContentType() == ContentType::ImIsComposing) {
onIsComposingReceived(msg->getFromAddress(), msg->getPrivate()->getText());
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) {
goto end;
}
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1)
return reason;
} else if (msg->getPrivate()->getContentType() == ContentType::Imdn) {
onImdnReceived(msg);
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1) {
goto end;
}
if (lp_config_get_int(linphone_core_get_config(cCore), "sip", "deliver_imdn", 0) != 1)
return reason;
}
onChatMessageReceived(msg);
end:
return reason;
}
@ -286,9 +328,16 @@ ChatRoom::ChatRoom (ChatRoomPrivate &p, const shared_ptr<Core> &core, const Chat
L_D();
d->chatRoomId = chatRoomId;
d->imdnHandler.reset(new Imdn(this));
d->isComposingHandler.reset(new IsComposing(core->getCCore(), d));
}
ChatRoom::~ChatRoom () {
L_D();
d->imdnHandler.reset();
}
// -----------------------------------------------------------------------------
const ChatRoomId &ChatRoom::getChatRoomId () const {
@ -377,7 +426,11 @@ int ChatRoom::getChatMessageCount () const {
}
int ChatRoom::getUnreadChatMessageCount () const {
return getCore()->getPrivate()->mainDb->getUnreadChatMessageCount(getChatRoomId());
L_D();
int dbUnreadCount = getCore()->getPrivate()->mainDb->getUnreadChatMessageCount(getChatRoomId());
int notifiedCount = d->imdnHandler->getDisplayNotificationCount();
L_ASSERT(dbUnreadCount >= notifiedCount);
return dbUnreadCount - notifiedCount;
}
// -----------------------------------------------------------------------------
@ -443,16 +496,21 @@ shared_ptr<ChatMessage> ChatRoom::findChatMessage (const string &messageId, Chat
void ChatRoom::markAsRead () {
L_D();
bool globallyMarkAsReadInDb = true;
CorePrivate *dCore = getCore()->getPrivate();
for (auto &chatMessage : dCore->mainDb->getUnreadChatMessages(d->chatRoomId)) {
// Do not send display notification for file transfer until it has been downloaded (it won't have a file transfer content anymore)
if (!chatMessage->getPrivate()->hasFileTransferContent()) {
chatMessage->sendDisplayNotification();
chatMessage->getPrivate()->setState(ChatMessage::State::Displayed, true); // True will ensure the setState won't update the database so it will be done below by the markChatMessagesAsRead
bool doNotStoreInDb = d->sendDisplayNotification(chatMessage);
// Force the state so it is stored directly in DB, but when the IMDN has successfully been delivered
chatMessage->getPrivate()->setState(ChatMessage::State::Displayed, doNotStoreInDb);
if (doNotStoreInDb)
globallyMarkAsReadInDb = false;
}
}
dCore->mainDb->markChatMessagesAsRead(d->chatRoomId);
if (globallyMarkAsReadInDb)
dCore->mainDb->markChatMessagesAsRead(d->chatRoomId);
}
LINPHONE_END_NAMESPACE

View file

@ -31,10 +31,14 @@ class ChatRoomPrivate;
class LINPHONE_PUBLIC ChatRoom : public AbstractChatRoom {
public:
friend class ChatMessagePrivate;
friend class Imdn;
friend class ImdnMessagePrivate;
friend class ProxyChatRoomPrivate;
L_OVERRIDE_SHARED_FROM_THIS(ChatRoom);
~ChatRoom ();
const ChatRoomId &getChatRoomId () const override;
const IdentityAddress &getPeerAddress () const override;

View file

@ -17,6 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <algorithm>
#include "linphone/utils/utils.h"
#include "address/address-p.h"
@ -118,13 +120,13 @@ void ClientGroupChatRoomPrivate::confirmJoining (SalCallOp *op) {
auto focus = qConference->getPrivate()->focus;
bool previousSession = (focus->getPrivate()->getSession() != nullptr);
auto session = focus->getPrivate()->createSession(*q, nullptr, false, this);
session->configure(LinphoneCallIncoming, nullptr, op, Address(op->get_from()), Address(op->get_to()));
session->configure(LinphoneCallIncoming, nullptr, op, Address(op->getFrom()), Address(op->getTo()));
session->startIncomingNotification(false);
if (!previousSession) {
setState(ClientGroupChatRoom::State::CreationPending);
// Handle participants addition
list<IdentityAddress> identAddresses = ClientGroupChatRoom::parseResourceLists(op->get_remote_body());
list<IdentityAddress> identAddresses = ClientGroupChatRoom::parseResourceLists(op->getRemoteBody());
for (const auto &addr : identAddresses) {
auto participant = q->findParticipant(addr);
if (!participant) {
@ -181,7 +183,7 @@ void ClientGroupChatRoomPrivate::onCallSessionStateChanged (
} else if (q->getState() == ChatRoom::State::TerminationPending)
qConference->getPrivate()->focus->getPrivate()->getSession()->terminate();
} else if (newState == CallSession::State::End) {
q->onConferenceTerminated(q->getConferenceAddress());
setState(ChatRoom::State::TerminationPending);
} else if (newState == CallSession::State::Released) {
if (q->getState() == ChatRoom::State::TerminationPending) {
if (session->getReason() == LinphoneReasonNone) {
@ -346,22 +348,7 @@ void ClientGroupChatRoom::deleteFromDb () {
}
void ClientGroupChatRoom::addParticipant (const IdentityAddress &addr, const CallSessionParams *params, bool hasMedia) {
list<IdentityAddress> addresses;
addresses.push_back(addr);
addParticipants(addresses, params, hasMedia);
}
void ClientGroupChatRoom::addParticipants (
const list<IdentityAddress> &addresses,
const CallSessionParams *params,
bool hasMedia
) {
L_D();
L_D_T(RemoteConference, dConference);
list<IdentityAddress> addressesList = d->cleanAddressesList(addresses);
if (addressesList.empty())
return;
if ((getState() != ChatRoom::State::Instantiated) && (getState() != ChatRoom::State::Created)) {
lError() << "Cannot add participants to the ClientGroupChatRoom in a state other than Instantiated or Created";
@ -373,6 +360,41 @@ void ClientGroupChatRoom::addParticipants (
return;
}
LinphoneCore *cCore = getCore()->getCCore();
if (getState() == ChatRoom::State::Instantiated) {
list<IdentityAddress> addressesList;
addressesList.push_back(addr);
Content content;
content.setBody(getResourceLists(addressesList));
content.setContentType(ContentType::ResourceLists);
content.setContentDisposition(ContentDisposition::RecipientList);
auto session = d->createSession();
session->startInvite(nullptr, getSubject(), &content);
d->setState(ChatRoom::State::CreationPending);
} else {
SalReferOp *referOp = new SalReferOp(cCore->sal);
LinphoneAddress *lAddr = linphone_address_new(getConferenceAddress().asString().c_str());
linphone_configure_op(cCore, referOp, lAddr, nullptr, true);
linphone_address_unref(lAddr);
Address referToAddr = addr;
referToAddr.setParam("text");
referOp->sendRefer(referToAddr.getPrivate()->getInternalAddress());
referOp->unref();
}
}
void ClientGroupChatRoom::addParticipants (
const list<IdentityAddress> &addresses,
const CallSessionParams *params,
bool hasMedia
) {
L_D();
list<IdentityAddress> addressesList = d->cleanAddressesList(addresses);
if (addressesList.empty())
return;
if ((getState() == ChatRoom::State::Instantiated)
&& (addressesList.size() == 1)
&& (linphone_config_get_bool(linphone_core_get_config(L_GET_C_BACK_PTR(getCore())),
@ -381,23 +403,20 @@ void ClientGroupChatRoom::addParticipants (
d->capabilities |= ClientGroupChatRoom::Capabilities::OneToOne;
}
Content content;
content.setBody(getResourceLists(addressesList));
content.setContentType(ContentType::ResourceLists);
content.setContentDisposition(ContentDisposition::RecipientList);
// TODO: Activate compression
//if (linphone_core_content_encoding_supported(getCore()->getCCore(), "deflate"))
// content.setContentEncoding("deflate");
// TODO: Activate compression
if (getState() == ChatRoom::State::Instantiated) {
Content content;
content.setBody(getResourceLists(addressesList));
content.setContentType(ContentType::ResourceLists);
content.setContentDisposition(ContentDisposition::RecipientList);
if (linphone_core_content_encoding_supported(getCore()->getCCore(), "deflate"))
content.setContentEncoding("deflate");
shared_ptr<CallSession> session = dConference->focus->getPrivate()->getSession();
if (session)
session->update(nullptr, getSubject(), &content);
else {
session = d->createSession();
auto session = d->createSession();
session->startInvite(nullptr, getSubject(), &content);
if (getState() == ChatRoom::State::Instantiated)
d->setState(ChatRoom::State::CreationPending);
d->setState(ChatRoom::State::CreationPending);
} else {
for (const auto &addr : addresses)
addParticipant(addr, params, hasMedia);
}
}
@ -411,7 +430,7 @@ void ClientGroupChatRoom::removeParticipant (const shared_ptr<Participant> &part
Address referToAddr = participant->getAddress();
referToAddr.setParam("text");
referToAddr.setUriParam("method", "BYE");
referOp->send_refer(referToAddr.getPrivate()->getInternalAddress());
referOp->sendRefer(referToAddr.getPrivate()->getInternalAddress());
referOp->unref();
}
@ -453,7 +472,7 @@ void ClientGroupChatRoom::setParticipantAdminStatus (const shared_ptr<Participan
Address referToAddr = participant->getAddress();
referToAddr.setParam("text");
referToAddr.setParam("admin", Utils::toString(isAdmin));
referOp->send_refer(referToAddr.getPrivate()->getInternalAddress());
referOp->sendRefer(referToAddr.getPrivate()->getInternalAddress());
referOp->unref();
}
@ -532,7 +551,8 @@ void ClientGroupChatRoom::onConferenceCreated (const IdentityAddress &addr) {
void ClientGroupChatRoom::onConferenceKeywordsChanged (const vector<string> &keywords) {
L_D();
d->capabilities |= ClientGroupChatRoom::Capabilities::OneToOne;
if (find(keywords.cbegin(), keywords.cend(), "one-to-one") != keywords.cend())
d->capabilities |= ClientGroupChatRoom::Capabilities::OneToOne;
}
void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) {
@ -555,6 +575,12 @@ void ClientGroupChatRoom::onConferenceTerminated (const IdentityAddress &addr) {
void ClientGroupChatRoom::onFirstNotifyReceived (const IdentityAddress &addr) {
L_D();
if (getState() != ChatRoom::State::Created) {
lWarning() << "First notify received in ClientGroupChatRoom that is not in the Created state, ignoring it!";
return;
}
bool performMigration = false;
shared_ptr<AbstractChatRoom> chatRoom;
if (getParticipantCount() == 1) {

View file

@ -57,6 +57,10 @@ public:
chatRoom->getPrivate()->removeTransientEvent(eventLog);
}
inline void sendDeliveryNotifications () override {
chatRoom->getPrivate()->sendDeliveryNotifications();
}
inline void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override {
chatRoom->getPrivate()->notifyChatMessageReceived(chatMessage);
}

View file

@ -21,7 +21,7 @@
#include "call/call.h"
#include "chat/chat-message/chat-message-p.h"
#include "conference/participant.h"
#include "core/core.h"
#include "core/core-p.h"
#include "logger/logger.h"
#include "real-time-text-chat-room-p.h"
@ -43,8 +43,13 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, cons
LinphoneCore *cCore = core->getCCore();
if (call && call->getCurrentParams()->realtimeTextEnabled()) {
if (!pendingMessage)
pendingMessage = q->createChatMessage("");
if (!pendingMessage) {
pendingMessage = q->createChatMessage();
pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming);
Content *content = new Content();
content->setContentType(ContentType::PlainText);
pendingMessage->addContent(content);
}
Character cmc;
cmc.value = character;
@ -56,23 +61,24 @@ void RealTimeTextChatRoomPrivate::realtimeTextReceived (uint32_t character, cons
if ((character == new_line) || (character == crlf) || (character == lf)) {
// End of message
lDebug() << "New line received, forge a message with content " << pendingMessage->getPrivate()->getText().c_str();
auto content = pendingMessage->getContents().front();
lDebug() << "New line received, forge a message with content " << content->getBodyAsString();
pendingMessage->getPrivate()->setState(ChatMessage::State::Delivered);
pendingMessage->getPrivate()->setDirection(ChatMessage::Direction::Incoming);
pendingMessage->getPrivate()->setTime(::ms_time(0));
if (lp_config_get_int(linphone_core_get_config(cCore), "misc", "store_rtt_messages", 1) == 1)
pendingMessage->getPrivate()->storeInDb();
pendingMessage->setToBeStored(true);
else
pendingMessage->setToBeStored(false);
onChatMessageReceived(pendingMessage);
pendingMessage = nullptr;
receivedRttCharacters.clear();
} else {
char *value = Utils::utf8ToChar(character);
string text(pendingMessage->getPrivate()->getText());
text += string(value);
pendingMessage->getPrivate()->setText(text);
lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << pendingMessage->getPrivate()->getText();
auto content = pendingMessage->getContents().front();
content->setBody(content->getBodyAsString() + string(value));
lDebug() << "Received RTT character: " << value << " (" << character << "), pending text is " << content->getBodyAsString();
delete[] value;
}
}
@ -84,6 +90,16 @@ void RealTimeTextChatRoomPrivate::sendChatMessage (const shared_ptr<ChatMessage>
if (call && call->getCurrentParams()->realtimeTextEnabled()) {
uint32_t newLine = 0x2028;
chatMessage->putCharacter(newLine);
ChatMessagePrivate *dChatMessage = chatMessage->getPrivate();
shared_ptr<ConferenceChatMessageEvent> event = static_pointer_cast<ConferenceChatMessageEvent>(
q->getCore()->getPrivate()->mainDb->getEventFromKey(dChatMessage->dbKey)
);
if (!event)
event = make_shared<ConferenceChatMessageEvent>(time(nullptr), chatMessage);
LinphoneChatRoom *cr = getCChatRoom();
_linphone_chat_room_notify_chat_message_sent(cr, L_GET_C_BACK_PTR(event));
}
}

View file

@ -69,7 +69,7 @@ public:
private:
struct Message {
Message (const std::string &from, const ContentType &contentType, const std::string &text, const SalCustomHeader *salCustomHeaders)
: fromAddr(from)
: fromAddr(from)
{
content.setContentType(contentType);
if (!text.empty())

View file

@ -139,8 +139,8 @@ void ServerGroupChatRoomPrivate::onCallSessionSetReleased (const shared_ptr<Call
// =============================================================================
ServerGroupChatRoom::ServerGroupChatRoom (const shared_ptr<Core> &core, SalCallOp *op)
: ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(op->get_to()), IdentityAddress(op->get_to()))),
LocalConference(core, IdentityAddress(op->get_to()), nullptr) {
: ChatRoom(*new ServerGroupChatRoomPrivate, core, ChatRoomId(IdentityAddress(op->getTo()), IdentityAddress(op->getTo()))),
LocalConference(core, IdentityAddress(op->getTo()), nullptr) {
L_D();
d->chatRoomListener = d;
}

View file

@ -17,6 +17,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <iomanip>
#include <sstream>
#include "linphone/utils/utils.h"
#include "logger/logger.h"
#include "chat/cpim/parser/cpim-parser.h"
#include "cpim-header-p.h"
@ -28,51 +35,278 @@ using namespace std;
LINPHONE_BEGIN_NAMESPACE
Cpim::CoreHeader::CoreHeader () : Header(*new HeaderPrivate) {}
class Cpim::ContactHeaderPrivate : public HeaderPrivate {
public:
string uri;
string formalName;
};
Cpim::CoreHeader::CoreHeader (HeaderPrivate &p) : Header(p) {}
Cpim::ContactHeader::ContactHeader () : Header(*new ContactHeaderPrivate) {}
Cpim::CoreHeader::~CoreHeader () {}
Cpim::ContactHeader::ContactHeader (const string &uri, const string &formalName) : ContactHeader() {
setUri(uri);
setFormalName(formalName);
}
bool Cpim::CoreHeader::isValid () const {
return !getValue().empty();
string Cpim::ContactHeader::getUri () const {
L_D();
return d->uri;
}
void Cpim::ContactHeader::setUri (const string &uri) {
L_D();
d->uri = uri;
}
string Cpim::ContactHeader::getFormalName () const {
L_D();
return d->formalName;
}
void Cpim::ContactHeader::setFormalName (const string &formalName) {
L_D();
if (formalName.front() == '\"' && formalName.back() == '\"')
d->formalName = formalName.substr(1, formalName.size() - 2);
else if (formalName.back() == ' ')
d->formalName = formalName.substr(0, formalName.size() - 1);
else
d->formalName = formalName;
}
string Cpim::ContactHeader::getValue () const {
L_D();
string result;
if (!d->formalName.empty())
result += "\"" + d->formalName + "\"";
result += "<" + d->uri + ">";
return result;
}
string Cpim::ContactHeader::asString () const {
return getName() + ": " + getValue() + "\r\n";
}
// -----------------------------------------------------------------------------
#define MAKE_CORE_HEADER_IMPL(CLASS_PREFIX) \
bool Cpim::CLASS_PREFIX ## Header::setValue(const string &value) { \
return Parser::getInstance()->coreHeaderIsValid<CLASS_PREFIX ## Header>(value) && Header::setValue(value); \
class Cpim::DateTimeHeaderPrivate : public HeaderPrivate {
public:
tm dateTime;
tm dateTimeOffset;
string signOffset;
};
Cpim::DateTimeHeader::DateTimeHeader () : Header(*new DateTimeHeaderPrivate) {}
Cpim::DateTimeHeader::DateTimeHeader (time_t time) : DateTimeHeader() {
setTime(time);
}
Cpim::DateTimeHeader::DateTimeHeader (const tm &time, const tm &timeOffset, const string &signOffset) : DateTimeHeader() {
setTime(time, timeOffset, signOffset);
}
time_t Cpim::DateTimeHeader::getTime () const {
L_D();
tm result = d->dateTime;
result.tm_year -= 1900;
result.tm_isdst = 0;
if (d->signOffset == "+") {
result.tm_hour += d->dateTimeOffset.tm_hour;
result.tm_min += d->dateTimeOffset.tm_min;
while (result.tm_min > 59) {
result.tm_hour++;
result.tm_min -= 60;
}
}
else if (d->signOffset == "-") {
result.tm_hour -= d->dateTimeOffset.tm_hour;
result.tm_hour -= d->dateTimeOffset.tm_min;
while (result.tm_min < 0) {
result.tm_hour--;
result.tm_min += 60;
}
}
MAKE_CORE_HEADER_IMPL(From);
MAKE_CORE_HEADER_IMPL(To);
MAKE_CORE_HEADER_IMPL(Cc);
MAKE_CORE_HEADER_IMPL(DateTime);
MAKE_CORE_HEADER_IMPL(MessageId);
return Utils::getTmAsTimeT(result);
}
MAKE_CORE_HEADER_IMPL(Ns);
MAKE_CORE_HEADER_IMPL(Require);
void Cpim::DateTimeHeader::setTime (const time_t time) {
L_D();
#undef MAKE_CORE_HEADER_IMPL
d->signOffset = "Z";
d->dateTime = Utils::getTimeTAsTm(time);
d->dateTime.tm_year += 1900;
}
void Cpim::DateTimeHeader::setTime (const tm &time, const tm &timeOffset, const string &signOffset) {
L_D();
d->dateTime = time;
d->dateTimeOffset = timeOffset;
d->signOffset = signOffset;
}
string Cpim::DateTimeHeader::getValue () const {
L_D();
stringstream ss;
ss << setfill('0') << setw(4) << d->dateTime.tm_year << "-"
<< setfill('0') << setw(2) << d->dateTime.tm_mon + 1 << "-"
<< setfill('0') << setw(2) << d->dateTime.tm_mday << "T"
<< setfill('0') << setw(2) << d->dateTime.tm_hour << ":"
<< setfill('0') << setw(2) << d->dateTime.tm_min << ":"
<< setfill('0') << setw(2) << d->dateTime.tm_sec;
ss << d->signOffset;
if (d->signOffset != "Z")
ss << setfill('0') << setw(2) << d->dateTimeOffset.tm_hour << ":"
<< setfill('0') << setw(2) << d->dateTimeOffset.tm_min;
return ss.str();
}
string Cpim::DateTimeHeader::asString () const {
return getName() + ": " + getValue() + "\r\n";
}
struct tm Cpim::DateTimeHeader::getTimeStruct () const {
L_D();
return d->dateTime;
}
struct tm Cpim::DateTimeHeader::getTimeOffset () const {
L_D();
return d->dateTimeOffset;
}
string Cpim::DateTimeHeader::getSignOffset () const {
L_D();
return d->signOffset;
}
// -----------------------------------------------------------------------------
void Cpim::CoreHeader::force (const string &value) {
Header::setValue(value);
class Cpim::NsHeaderPrivate : public HeaderPrivate {
public:
string uri;
string prefixName;
};
Cpim::NsHeader::NsHeader () : Header(*new NsHeaderPrivate) {}
Cpim::NsHeader::NsHeader (const string &uri, const string &prefixName) : NsHeader() {
setUri(uri);
setPrefixName(prefixName);
}
string Cpim::NsHeader::getUri () const {
L_D();
return d->uri;
}
void Cpim::NsHeader::setUri (const string &uri) {
L_D();
d->uri = uri;
}
string Cpim::NsHeader::getPrefixName () const {
L_D();
return d->prefixName;
}
void Cpim::NsHeader::setPrefixName (const string &prefixName) {
L_D();
d->prefixName = prefixName;
}
string Cpim::NsHeader::getValue () const {
L_D();
string ns;
if (!d->prefixName.empty())
ns = d->prefixName + " ";
return ns + "<" + d->uri + ">";
}
string Cpim::NsHeader::asString () const {
return getName() + ": " + getValue() + "\r\n";
}
// -----------------------------------------------------------------------------
class Cpim::RequireHeaderPrivate : public HeaderPrivate {
public:
list<string> headerNames;
};
Cpim::RequireHeader::RequireHeader () : Header(*new RequireHeaderPrivate) {}
Cpim::RequireHeader::RequireHeader (const string &headerNames) : RequireHeader() {
for (const string &header : Utils::split(headerNames, ",")) {
addHeaderName(header);
}
}
Cpim::RequireHeader::RequireHeader (const list<string> &headerNames) : RequireHeader() {
L_D();
d->headerNames = headerNames;
}
list<string> Cpim::RequireHeader::getHeaderNames () const {
L_D();
return d->headerNames;
}
void Cpim::RequireHeader::addHeaderName (const string &headerName) {
L_D();
d->headerNames.push_back(headerName);
}
string Cpim::RequireHeader::getValue () const {
L_D();
string requires;
for (const string &header : d->headerNames) {
if (header != d->headerNames.front())
requires += ",";
requires += header;
}
return requires;
}
string Cpim::RequireHeader::asString () const {
return getName() + ": " + getValue() + "\r\n";
}
// -----------------------------------------------------------------------------
class Cpim::SubjectHeaderPrivate : public HeaderPrivate {
public:
string subject;
string language;
};
Cpim::SubjectHeader::SubjectHeader () : CoreHeader(*new SubjectHeaderPrivate) {}
Cpim::SubjectHeader::SubjectHeader () : Header(*new SubjectHeaderPrivate) {}
bool Cpim::SubjectHeader::setValue (const string &value) {
return Parser::getInstance()->coreHeaderIsValid<SubjectHeader>(value) && Header::setValue(value);
Cpim::SubjectHeader::SubjectHeader (const string &subject, const string &language) : SubjectHeader() {
setSubject(subject);
setLanguage(language);
}
string Cpim::SubjectHeader::getSubject () const {
L_D();
return d->subject;
}
void Cpim::SubjectHeader::setSubject (const string &subject) {
L_D();
d->subject = subject;
}
string Cpim::SubjectHeader::getLanguage () const {
@ -80,30 +314,23 @@ string Cpim::SubjectHeader::getLanguage () const {
return d->language;
}
bool Cpim::SubjectHeader::setLanguage (const string &language) {
if (!language.empty() && !Parser::getInstance()->subjectHeaderLanguageIsValid(language))
return false;
void Cpim::SubjectHeader::setLanguage (const string &language) {
L_D();
d->language = language;
return true;
}
string Cpim::SubjectHeader::asString () const {
string Cpim::SubjectHeader::getValue () const {
L_D();
string languageParam;
if (!d->language.empty())
languageParam = ";lang=" + d->language;
return getName() + ":" + languageParam + " " + getValue() + "\r\n";
return languageParam + " " + d->subject;
}
void Cpim::SubjectHeader::force (const string &value, const string &language) {
L_D();
CoreHeader::force(value);
d->language = language;
string Cpim::SubjectHeader::asString () const {
return getName() + ":" + getValue() + "\r\n";
}
LINPHONE_END_NAMESPACE

View file

@ -20,61 +20,160 @@
#ifndef _L_CPIM_CORE_HEADERS_H_
#define _L_CPIM_CORE_HEADERS_H_
#include <ctime>
#include <list>
#include "cpim-header.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
#define MAKE_CORE_HEADER(CLASS_PREFIX, NAME) \
class LINPHONE_PUBLIC CLASS_PREFIX ## Header : public CoreHeader { \
#define MAKE_CONTACT_HEADER(CLASS_PREFIX, NAME) \
class LINPHONE_PUBLIC CLASS_PREFIX ## Header : public ContactHeader { \
public: \
CLASS_PREFIX ## Header() = default; \
inline std::string getName() const override { \
CLASS_PREFIX ## Header () = default; \
CLASS_PREFIX ## Header (const std::string &uri, const std::string &formalName = "") : ContactHeader (uri, formalName) {} \
inline std::string getName () const override { \
return NAME; \
} \
bool setValue(const std::string &value) override; \
private: \
L_DISABLE_COPY(CLASS_PREFIX ## Header); \
};
namespace Cpim {
class HeaderNode;
class DateTimeHeaderNode;
// -------------------------------------------------------------------------
// Generic core header.
// Specific Contact headers declaration.
// -------------------------------------------------------------------------
class LINPHONE_PUBLIC CoreHeader : public Header {
friend class HeaderNode;
class ContactHeaderPrivate;
class LINPHONE_PUBLIC ContactHeader : public Header {
public:
CoreHeader ();
ContactHeader ();
virtual ~CoreHeader () = 0;
ContactHeader (const std::string &uri, const std::string &formalName = "");
bool isValid () const override;
std::string getUri () const;
void setUri (const std::string &uri);
protected:
explicit CoreHeader (HeaderPrivate &p);
std::string getFormalName () const;
void setFormalName (const std::string &formalName);
void force (const std::string &value);
std::string getValue () const override;
std::string asString () const override;
private:
L_DISABLE_COPY(CoreHeader);
L_DECLARE_PRIVATE(ContactHeader);
L_DISABLE_COPY(ContactHeader);
};
// -------------------------------------------------------------------------
// Core headers.
MAKE_CONTACT_HEADER(From, "From");
MAKE_CONTACT_HEADER(To, "To");
MAKE_CONTACT_HEADER(Cc, "cc");
// -------------------------------------------------------------------------
// Specific DateTime declaration.
// -------------------------------------------------------------------------
MAKE_CORE_HEADER(From, "From");
MAKE_CORE_HEADER(To, "To");
MAKE_CORE_HEADER(Cc, "cc");
MAKE_CORE_HEADER(DateTime, "DateTime");
MAKE_CORE_HEADER(MessageId, "Message-ID");
MAKE_CORE_HEADER(Ns, "NS");
MAKE_CORE_HEADER(Require, "Require");
class DateTimeHeaderPrivate;
class LINPHONE_PUBLIC DateTimeHeader : public Header {
friend class DateTimeHeaderNode;
public:
DateTimeHeader ();
DateTimeHeader (time_t time);
DateTimeHeader (const tm &time, const tm &timeOffset, const std::string &signOffset);
inline std::string getName () const override {
return "DateTime";
}
time_t getTime () const;
void setTime (const time_t time);
void setTime (const tm &time, const tm &timeOffset, const std::string &signOffset);
std::string getValue () const override;
std::string asString () const override;
private:
tm getTimeStruct () const;
tm getTimeOffset () const;
std::string getSignOffset () const;
L_DECLARE_PRIVATE(DateTimeHeader);
L_DISABLE_COPY(DateTimeHeader);
};
// -------------------------------------------------------------------------
// Specific Ns declaration.
// -------------------------------------------------------------------------
class NsHeaderPrivate;
class LINPHONE_PUBLIC NsHeader : public Header {
public:
NsHeader ();
NsHeader (const std::string &uri, const std::string &prefixName = "");
inline std::string getName () const override {
return "NS";
}
std::string getPrefixName () const;
void setPrefixName (const std::string &prefixName);
std::string getUri () const;
void setUri (const std::string &uri);
std::string getValue () const override;
std::string asString () const override;
private:
L_DECLARE_PRIVATE(NsHeader);
L_DISABLE_COPY(NsHeader);
};
// -------------------------------------------------------------------------
// Specific Require declaration.
// -------------------------------------------------------------------------
class RequireHeaderPrivate;
class LINPHONE_PUBLIC RequireHeader : public Header {
public:
RequireHeader ();
RequireHeader (const std::string &headerNames);
RequireHeader (const std::list<std::string> &headerNames);
inline std::string getName () const override {
return "Require";
}
std::list<std::string> getHeaderNames () const;
void addHeaderName (const std::string &headerName);
std::string getValue () const override;
std::string asString () const override;
private:
L_DECLARE_PRIVATE(RequireHeader);
L_DISABLE_COPY(RequireHeader);
};
// -------------------------------------------------------------------------
// Specific Subject declaration.
@ -82,33 +181,33 @@ namespace Cpim {
class SubjectHeaderPrivate;
class LINPHONE_PUBLIC SubjectHeader : public CoreHeader {
friend class HeaderNode;
class LINPHONE_PUBLIC SubjectHeader : public Header {
public:
SubjectHeader ();
SubjectHeader (const std::string &subject, const std::string &language = "");
inline std::string getName () const override {
return "Subject";
}
bool setValue (const std::string &value) override;
std::string getSubject () const;
void setSubject (const std::string &subject);
std::string getLanguage () const;
bool setLanguage (const std::string &language);
void setLanguage (const std::string &language);
std::string getValue () const override;
std::string asString () const override;
protected:
void force (const std::string &value, const std::string &language);
private:
L_DECLARE_PRIVATE(SubjectHeader);
L_DISABLE_COPY(SubjectHeader);
};
}
#undef MAKE_CORE_HEADER
#undef MAKE_CONTACT_HEADER
LINPHONE_END_NAMESPACE

View file

@ -34,38 +34,50 @@ LINPHONE_BEGIN_NAMESPACE
class Cpim::GenericHeaderPrivate : public HeaderPrivate {
public:
GenericHeaderPrivate () : parameters(make_shared<list<pair<string, string> > >()) {}
GenericHeaderPrivate () : parameters(make_shared<list<pair<string, string>>>()) {}
string name;
shared_ptr<list<pair<string, string> > > parameters;
string value;
shared_ptr<list<pair<string, string>>> parameters;
};
Cpim::GenericHeader::GenericHeader () : Header(*new GenericHeaderPrivate) {}
Cpim::GenericHeader::GenericHeader (string name, string value, string parameters) : GenericHeader() {
setName(name);
setValue(value);
for (const auto &parameter : Utils::split(parameters, ';')) {
size_t equalIndex = parameter.find('=');
if (equalIndex != string::npos)
addParameter(parameter.substr(0, equalIndex), parameter.substr(equalIndex + 1));
}
}
string Cpim::GenericHeader::getName () const {
L_D();
return d->name;
}
bool Cpim::GenericHeader::setName (const string &name) {
void Cpim::GenericHeader::setName (const string &name) {
L_D();
static const set<string> reserved = {
"From", "To", "cc", "DateTime", "Subject", "NS", "Require"
};
if (
reserved.find(name) != reserved.end() ||
!Parser::getInstance()->headerNameIsValid(name)
)
return false;
d->name = name;
return true;
if (reserved.find(name) == reserved.end())
d->name = name;
}
bool Cpim::GenericHeader::setValue (const string &value) {
return Parser::getInstance()->headerValueIsValid(value) && Header::setValue(value);
string Cpim::GenericHeader::getValue () const {
L_D();
return d->value;
}
void Cpim::GenericHeader::setValue (const string &value) {
L_D();
d->value = value;
}
Cpim::GenericHeader::ParameterList Cpim::GenericHeader::getParameters () const {
@ -73,14 +85,9 @@ Cpim::GenericHeader::ParameterList Cpim::GenericHeader::getParameters () const {
return d->parameters;
}
bool Cpim::GenericHeader::addParameter (const string &key, const string &value) {
void Cpim::GenericHeader::addParameter (const string &key, const string &value) {
L_D();
if (!Parser::getInstance()->headerParameterIsValid(key + "=" + value))
return false;
d->parameters->push_back(make_pair(key, value));
return true;
}
void Cpim::GenericHeader::removeParameter (const string &key, const string &value) {
@ -88,11 +95,6 @@ void Cpim::GenericHeader::removeParameter (const string &key, const string &valu
d->parameters->remove(make_pair(key, value));
}
bool Cpim::GenericHeader::isValid () const {
L_D();
return !d->name.empty() && !getValue().empty();
}
string Cpim::GenericHeader::asString () const {
L_D();
@ -103,21 +105,4 @@ string Cpim::GenericHeader::asString () const {
return d->name + ":" + parameters + " " + getValue() + "\r\n";
}
// -----------------------------------------------------------------------------
void Cpim::GenericHeader::force (const string &name, const string &value, const string &parameters) {
L_D();
// Set name/value.
d->name = name;
Header::setValue(value);
// Parse and build parameters list.
for (const auto &parameter : Utils::split(parameters, ';')) {
size_t equalIndex = parameter.find('=');
if (equalIndex != string::npos)
d->parameters->push_back(make_pair(parameter.substr(0, equalIndex), parameter.substr(equalIndex + 1)));
}
}
LINPHONE_END_NAMESPACE

View file

@ -38,24 +38,22 @@ namespace Cpim {
public:
GenericHeader ();
GenericHeader (std::string name, std::string value, std::string parameters = "");
std::string getName () const override;
bool setName (const std::string &name);
void setName (const std::string &name);
bool setValue (const std::string &value) override;
std::string getValue () const override;
void setValue (const std::string &value);
typedef std::shared_ptr<const std::list<std::pair<std::string, std::string> > > ParameterList;
typedef std::shared_ptr<const std::list<std::pair<std::string, std::string>>> ParameterList;
ParameterList getParameters () const;
bool addParameter (const std::string &key, const std::string &value);
void addParameter (const std::string &key, const std::string &value);
void removeParameter (const std::string &key, const std::string &value);
bool isValid () const override;
std::string asString () const override;
protected:
void force (const std::string &name, const std::string &value, const std::string &parameters);
private:
L_DECLARE_PRIVATE(GenericHeader);
L_DISABLE_COPY(GenericHeader);

View file

@ -30,8 +30,6 @@ LINPHONE_BEGIN_NAMESPACE
namespace Cpim {
class HeaderPrivate : public ObjectPrivate {
private:
std::string value;
L_DECLARE_PUBLIC(Header);
};
}

View file

@ -29,20 +29,4 @@ LINPHONE_BEGIN_NAMESPACE
Cpim::Header::Header (HeaderPrivate &p) : Object(p) {}
string Cpim::Header::getValue () const {
L_D();
return d->value;
}
bool Cpim::Header::setValue (const string &value) {
L_D();
d->value = value;
return true;
}
string Cpim::Header::asString () const {
L_D();
return getName() + ": " + d->value + "\r\n";
}
LINPHONE_END_NAMESPACE

View file

@ -35,12 +35,9 @@ namespace Cpim {
virtual std::string getName () const = 0;
std::string getValue () const;
virtual bool setValue (const std::string &value);
virtual std::string getValue () const = 0;
virtual bool isValid () const = 0;
virtual std::string asString () const;
virtual std::string asString () const = 0;
protected:
explicit Header (HeaderPrivate &p);

View file

@ -18,6 +18,7 @@
*/
#include <algorithm>
#include <map>
#include "linphone/utils/utils.h"
@ -36,10 +37,10 @@ LINPHONE_BEGIN_NAMESPACE
class Cpim::MessagePrivate : public ObjectPrivate {
public:
typedef list<shared_ptr<const Header> > PrivHeaderList;
using PrivHeaderList = list<shared_ptr<const Header>>;
using PrivHeaderMap = map<string, shared_ptr<PrivHeaderList>>;
shared_ptr<PrivHeaderList> cpimHeaders = make_shared<PrivHeaderList>(); // TODO: Remove this useless variable
shared_ptr<PrivHeaderList> messageHeaders = make_shared<PrivHeaderList>();
PrivHeaderMap messageHeaders;
shared_ptr<PrivHeaderList> contentHeaders = make_shared<PrivHeaderList>();
string content;
};
@ -48,50 +49,47 @@ Cpim::Message::Message () : Object(*new MessagePrivate) {}
// -----------------------------------------------------------------------------
Cpim::Message::HeaderList Cpim::Message::getCpimHeaders () const {
Cpim::Message::HeaderList Cpim::Message::getMessageHeaders (const string &ns) const {
L_D();
return d->cpimHeaders;
if (d->messageHeaders.find(ns) == d->messageHeaders.end())
return nullptr;
return d->messageHeaders.at(ns);
}
bool Cpim::Message::addCpimHeader (const Header &cpimHeader) {
void Cpim::Message::addMessageHeader (const Header &messageHeader, const string &ns) {
L_D();
if (!cpimHeader.isValid())
return false;
if (d->messageHeaders.find(ns) == d->messageHeaders.end())
d->messageHeaders[ns] = make_shared<Cpim::MessagePrivate::PrivHeaderList>();
d->cpimHeaders->push_back(Parser::getInstance()->cloneHeader(cpimHeader));
return true;
auto list = d->messageHeaders.at(ns);
list->push_back(Parser::getInstance()->cloneHeader(messageHeader));
}
void Cpim::Message::removeCpimHeader (const Header &cpimHeader) {
void Cpim::Message::removeMessageHeader (const Header &messageHeader, const string &ns) {
L_D();
d->cpimHeaders->remove_if([&cpimHeader](const shared_ptr<const Header> &header) {
return cpimHeader.getName() == header->getName() && cpimHeader.getValue() == header->getValue();
});
if (d->messageHeaders.find(ns) != d->messageHeaders.end())
d->messageHeaders.at(ns)->remove_if([&messageHeader](const shared_ptr<const Header> &header) {
return messageHeader.getName() == header->getName() && messageHeader.getValue() == header->getValue();
});
}
// -----------------------------------------------------------------------------
Cpim::Message::HeaderList Cpim::Message::getMessageHeaders () const {
L_D();
return d->messageHeaders;
}
bool Cpim::Message::addMessageHeader (const Header &messageHeader) {
shared_ptr<const Cpim::Header> Cpim::Message::getMessageHeader (const string &name, const string &ns) const {
L_D();
if (!messageHeader.isValid())
return false;
if (d->messageHeaders.find(ns) == d->messageHeaders.end())
return nullptr;
d->messageHeaders->push_back(Parser::getInstance()->cloneHeader(messageHeader));
return true;
}
auto list = d->messageHeaders.at(ns);
for (const auto &messageHeader : *list) {
if (messageHeader->getName() == name)
return messageHeader;
}
void Cpim::Message::removeMessageHeader (const Header &messageHeader) {
L_D();
d->messageHeaders->remove_if([&messageHeader](const shared_ptr<const Header> &header) {
return messageHeader.getName() == header->getName() && messageHeader.getValue() == header->getValue();
});
return nullptr;
}
// -----------------------------------------------------------------------------
@ -101,14 +99,9 @@ Cpim::Message::HeaderList Cpim::Message::getContentHeaders () const {
return d->contentHeaders;
}
bool Cpim::Message::addContentHeader (const Header &contentHeader) {
void Cpim::Message::addContentHeader (const Header &contentHeader) {
L_D();
if (!contentHeader.isValid())
return false;
d->contentHeaders->push_back(Parser::getInstance()->cloneHeader(contentHeader));
return true;
}
void Cpim::Message::removeContentHeader (const Header &contentHeader) {
@ -118,6 +111,17 @@ void Cpim::Message::removeContentHeader (const Header &contentHeader) {
});
}
shared_ptr<const Cpim::Header> Cpim::Message::getContentHeader(const string &name) const {
L_D();
for (const auto &contentHeader : *d->contentHeaders) {
if (contentHeader->getName() == name)
return contentHeader;
}
return nullptr;
}
// -----------------------------------------------------------------------------
string Cpim::Message::getContent () const {
@ -133,32 +137,19 @@ bool Cpim::Message::setContent (const string &content) {
// -----------------------------------------------------------------------------
bool Cpim::Message::isValid () const {
L_D();
return find_if(d->cpimHeaders->cbegin(), d->cpimHeaders->cend(),
[](const shared_ptr<const Header> &header) {
return Utils::iequals(header->getName(), "content-type") && (ContentType(header->getValue()) == ContentType::Cpim);
}) != d->cpimHeaders->cend();
}
// -----------------------------------------------------------------------------
string Cpim::Message::asString () const {
L_D();
string output;
// TODO: Remove cpimHeaders
if (d->cpimHeaders->size() > 0) {
for (const auto &cpimHeader : *d->cpimHeaders)
output += cpimHeader->asString();
output += "\r\n";
}
// TODO Remove cpimHeaders
if (d->messageHeaders->size() > 0) {
for (const auto &messageHeader : *d->messageHeaders)
output += messageHeader->asString();
if (d->messageHeaders.size() > 0) {
for (const auto &entry : d->messageHeaders) {
auto list = entry.second;
for (const auto &messageHeader : *list) {
if (entry.first != "")
output += entry.first + ".";
output += messageHeader->asString();
}
}
output += "\r\n";
}

View file

@ -34,27 +34,21 @@ namespace Cpim {
public:
Message ();
typedef std::shared_ptr<std::list<std::shared_ptr<const Cpim::Header> > > HeaderList;
typedef std::shared_ptr<std::list<std::shared_ptr<const Cpim::Header>>> HeaderList;
// TODO: Remove these useless methods
HeaderList getCpimHeaders () const;
bool addCpimHeader (const Header &cpimHeader);
void removeCpimHeader (const Header &cpimHeader);
// TODO: Remove these useless methods
HeaderList getMessageHeaders (const std::string &ns = "") const;
void addMessageHeader (const Header &messageHeader, const std::string &ns = "");
void removeMessageHeader (const Header &messageHeader, const std::string &ns = "");
std::shared_ptr<const Cpim::Header> getMessageHeader (const std::string &name, const std::string &ns = "") const;
HeaderList getMessageHeaders () const;
bool addMessageHeader (const Header &messageHeader);
void removeMessageHeader (const Header &messageHeader);
HeaderList getContentHeaders () const;
bool addContentHeader (const Header &contentHeader);
void addContentHeader (const Header &contentHeader);
void removeContentHeader (const Header &contentHeader);
std::shared_ptr<const Cpim::Header> getContentHeader (const std::string &name) const;
std::string getContent () const;
bool setContent (const std::string &content);
bool isValid () const; // TODO: Remove this useless method
std::string asString () const;
static std::shared_ptr<const Message> createFromString (const std::string &str);

View file

@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <unordered_map>
#include <set>
#include <belr/abnf.h>
#include <belr/grammarbuilder.h>
@ -53,20 +53,10 @@ namespace Cpim {
HeaderNode () = default;
explicit HeaderNode (const Header &header) : mName(header.getName()), mValue(header.getValue()) {
// Generic header.
const GenericHeader *genericHeader = dynamic_cast<const GenericHeader *>(&header);
if (genericHeader) {
for (const auto &parameter : *genericHeader->getParameters())
mParameters += ";" + parameter.first + "=" + parameter.second;
return;
}
// Subject header.
const SubjectHeader *subjectHeader = dynamic_cast<const SubjectHeader *>(&header);
if (subjectHeader) {
const string language = subjectHeader->getLanguage();
if (!language.empty())
mParameters = ";lang=" + language;
}
}
@ -75,7 +65,12 @@ namespace Cpim {
}
void setName (const string &name) {
mName = name;
static const set<string> reserved = {
"From", "To", "cc", "DateTime", "Subject", "NS", "Require"
};
if (reserved.find(name) == reserved.end())
mName = name;
}
string getParameters () const {
@ -94,68 +89,425 @@ namespace Cpim {
mValue = value;
}
shared_ptr<Header> createHeader (bool force) const;
virtual shared_ptr<Header> createHeader () const;
virtual bool isValid () const;
private:
template<typename T>
shared_ptr<Header> createCoreHeader (bool force) const {
shared_ptr<T> header = make_shared<T>();
if (force)
header->force(mValue);
else if (!header->setValue(mValue)) {
lWarning() << "Unable to set value on core header: `" << mName << "` => `" << mValue << "`.";
return nullptr;
}
return header;
}
string mName;
string mValue;
string mParameters;
};
template<>
shared_ptr<Header> HeaderNode::createCoreHeader<SubjectHeader>(bool force) const {
shared_ptr<SubjectHeader> header = make_shared<SubjectHeader>();
const string language = mParameters.length() >= 6 ? mParameters.substr(6) : "";
if (force)
header->force(mValue, language);
else if (!header->setValue(mValue) || (!language.empty() && !header->setLanguage(language))) {
lWarning() << "Unable to set value on subject header: `" <<
mName << "` => `" << mValue << "`, `" << language << "`.";
return nullptr;
}
return header;
bool HeaderNode::isValid () const {
return !mName.empty() && !mValue.empty();
}
shared_ptr<Header> HeaderNode::createHeader (bool force = false) const {
static const unordered_map<string, shared_ptr<Header>(HeaderNode::*)(bool)const> reservedHandlers = {
{ "From", &HeaderNode::createCoreHeader<FromHeader> },
{ "To", &HeaderNode::createCoreHeader<ToHeader> },
{ "cc", &HeaderNode::createCoreHeader<CcHeader> },
{ "DateTime", &HeaderNode::createCoreHeader<DateTimeHeader> },
{ "Message-ID", &HeaderNode::createCoreHeader<MessageIdHeader> },
{ "Subject", &HeaderNode::createCoreHeader<SubjectHeader> },
{ "NS", &HeaderNode::createCoreHeader<NsHeader> },
{ "Require", &HeaderNode::createCoreHeader<RequireHeader> }
};
shared_ptr<Header> HeaderNode::createHeader () const {
if (!isValid())
return nullptr;
// Core Header.
const auto it = reservedHandlers.find(mName);
if (it != reservedHandlers.cend())
return (this->*it->second)(force);
// Generic Header
shared_ptr<GenericHeader> genericHeader = make_shared<GenericHeader>();
genericHeader->force(mName, mValue, mParameters);
genericHeader->setName(mName);
for (const auto &parameter : Utils::split(mParameters, ';')) {
size_t equalIndex = parameter.find('=');
if (equalIndex != string::npos)
genericHeader->addParameter(parameter.substr(0, equalIndex), parameter.substr(equalIndex + 1));
}
genericHeader->setValue(mValue);
return genericHeader;
}
// -------------------------------------------------------------------------
class ContactHeaderNode : public HeaderNode {
public:
ContactHeaderNode () = default;
string getFormalName () const {
return mFormalName;
}
void setFormalName (const string &formalName) {
mFormalName = formalName;
}
string getUri () const {
return mUri;
}
void setUri (const string &uri) {
mUri = uri;
}
bool isValid () const override;
private:
string mFormalName;
string mUri;
};
bool ContactHeaderNode::isValid () const {
return !mUri.empty();
}
// -------------------------------------------------------------------------
class FromHeaderNode : public ContactHeaderNode {
public:
FromHeaderNode () = default;
explicit FromHeaderNode (const Header &header) {
const FromHeader *fromHeader = dynamic_cast<const FromHeader *>(&header);
if (fromHeader) {
setFormalName(fromHeader->getFormalName());
setUri(fromHeader->getUri());
}
}
shared_ptr<Header> createHeader () const override;
};
shared_ptr<Header> FromHeaderNode::createHeader () const {
if (!isValid())
return nullptr;
return make_shared<FromHeader>(getUri(), getFormalName());
}
// -------------------------------------------------------------------------
class ToHeaderNode : public ContactHeaderNode {
public:
ToHeaderNode () = default;
explicit ToHeaderNode (const Header &header) {
const ToHeader *toHeader = dynamic_cast<const ToHeader *>(&header);
if (toHeader) {
setFormalName(toHeader->getFormalName());
setUri(toHeader->getUri());
}
}
shared_ptr<Header> createHeader () const override;
};
shared_ptr<Header> ToHeaderNode::createHeader () const {
if (!isValid())
return nullptr;
return make_shared<ToHeader>(getUri(), getFormalName());
}
// -------------------------------------------------------------------------
class CcHeaderNode : public ContactHeaderNode {
public:
CcHeaderNode () = default;
explicit CcHeaderNode (const Header &header) {
const CcHeader *ccHeader = dynamic_cast<const CcHeader *>(&header);
if (ccHeader) {
setFormalName(ccHeader->getFormalName());
setUri(ccHeader->getUri());
}
}
shared_ptr<Header> createHeader () const override;
};
shared_ptr<Header> CcHeaderNode::createHeader () const {
if (!isValid())
return nullptr;
return make_shared<CcHeader>(getUri(), getFormalName());
}
// -------------------------------------------------------------------------
class DateTimeOffsetNode : public Node {
friend class DateTimeHeaderNode;
public:
DateTimeOffsetNode () {
mSign = "Z";
}
void setHour (const string &value) {
mHour = Utils::stoi(value);
}
void setMinute (const string &value) {
mMinute = Utils::stoi(value);
}
void setSign (const string &value) {
mSign = value;
}
private:
string mSign;
int mHour;
int mMinute;
};
class DateTimeHeaderNode : public HeaderNode {
public:
DateTimeHeaderNode () = default;
explicit DateTimeHeaderNode (const Header &header) {
const DateTimeHeader *dateTimeHeader = dynamic_cast<const DateTimeHeader *>(&header);
if (dateTimeHeader) {
setTime(dateTimeHeader->getTimeStruct());
setTimeOffset(dateTimeHeader->getTimeOffset());
setSignOffset(dateTimeHeader->getSignOffset());
}
}
struct tm getTime () const {
return mTime;
}
void setTime (const struct tm &time) {
mTime = time;
}
struct tm getTimeOffset () const {
return mTimeOffset;
}
void setTimeOffset (const struct tm &timeOffset) {
mTimeOffset = timeOffset;
}
string getSignOffset () const {
return mSignOffset;
}
void setSignOffset (const string &signOffset) {
mSignOffset = signOffset;
}
void setYear (const string &value) {
mTime.tm_year = Utils::stoi(value);
}
void setMonth (const string &value) {
mTime.tm_mon = Utils::stoi(value) - 1;
}
void setMonthDay (const string &value) {
mTime.tm_mday = Utils::stoi(value);
}
void setHour (const string &value) {
mTime.tm_hour = Utils::stoi(value);
}
void setMinute (const string &value) {
mTime.tm_min = Utils::stoi(value);
}
void setSecond (const string &value) {
mTime.tm_sec = Utils::stoi(value);
}
void setOffset (const shared_ptr<DateTimeOffsetNode> &offset) {
mTimeOffset.tm_hour = offset->mHour;
mTimeOffset.tm_min = offset->mMinute;
mSignOffset = offset->mSign;
}
bool isValid () const override;
shared_ptr<Header> createHeader() const override;
private:
tm mTime;
tm mTimeOffset;
string mSignOffset;
};
bool DateTimeHeaderNode::isValid () const {
static const int daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// Check date.
const bool isLeapYear = (mTime.tm_year % 4 == 0 && mTime.tm_year % 100 != 0) || mTime.tm_year % 400 == 0;
if (mTime.tm_mon < 1 || mTime.tm_mon > 12)
return false;
if (mTime.tm_mday < 1 || (mTime.tm_mon == 2 && isLeapYear ? mTime.tm_mday > 29 : mTime.tm_mday > daysInMonth[mTime.tm_mon - 1]))
return false;
// Check time.
if (mTime.tm_hour > 24 || mTime.tm_min > 59 || mTime.tm_sec > 60)
return false;
// Check num offset.
if (mSignOffset != "Z") {
if (mTimeOffset.tm_hour > 24 || mTime.tm_min > 59)
return false;
}
return true;
}
shared_ptr<Header> DateTimeHeaderNode::createHeader () const {
if (!isValid())
return nullptr;
return make_shared<DateTimeHeader>(getTime(), getTimeOffset(), getSignOffset());
}
// -------------------------------------------------------------------------
class SubjectHeaderNode : public HeaderNode {
public:
SubjectHeaderNode () = default;
explicit SubjectHeaderNode (const Header &header) {
const SubjectHeader *subjectHeader = dynamic_cast<const SubjectHeader *>(&header);
if (subjectHeader) {
setLanguage(subjectHeader->getLanguage());
setSubject(subjectHeader->getSubject());
}
}
string getLanguage () const {
return mLanguage;
}
void setLanguage (const string &language) {
mLanguage = language;
}
string getSubject () const {
return mSubject;
}
void setSubject (const string &subject) {
mSubject = subject;
}
bool isValid () const override;
shared_ptr<Header> createHeader () const override;
private:
string mLanguage;
string mSubject;
};
bool SubjectHeaderNode::isValid () const {
return !mSubject.empty();
}
shared_ptr<Header> SubjectHeaderNode::createHeader () const {
if (!isValid())
return nullptr;
return make_shared<SubjectHeader>(getSubject(), getLanguage());
}
// -------------------------------------------------------------------------
class NsHeaderNode : public HeaderNode {
public:
NsHeaderNode () = default;
explicit NsHeaderNode (const Header &header) {
const NsHeader *nsHeader = dynamic_cast<const NsHeader *>(&header);
if (nsHeader) {
setPrefixName(nsHeader->getPrefixName());
setUri(nsHeader->getUri());
}
}
string getPrefixName () const {
return mPrefixName;
}
void setPrefixName (const string &prefixName) {
mPrefixName = prefixName;
}
string getUri () const {
return mUri;
}
void setUri (const string &uri) {
mUri = uri;
}
bool isValid () const override;
shared_ptr<Header> createHeader () const override;
private:
string mPrefixName;
string mUri;
};
bool NsHeaderNode::isValid () const {
return !mUri.empty();
}
shared_ptr<Header> NsHeaderNode::createHeader () const {
if (!isValid())
return nullptr;
return make_shared<NsHeader>(getUri(), getPrefixName());
}
// -------------------------------------------------------------------------
class RequireHeaderNode : public HeaderNode {
public:
RequireHeaderNode () = default;
explicit RequireHeaderNode (const Header &header) {
const RequireHeader *requireHeader = dynamic_cast<const RequireHeader *>(&header);
if (requireHeader) {
for (const auto &header : requireHeader->getHeaderNames()) {
if (header != requireHeader->getHeaderNames().front())
mHeaderNames += ",";
mHeaderNames += header;
}
}
}
string getHeaderNames () const {
return mHeaderNames;
}
void setHeaderNames (const string &headerNames) {
mHeaderNames = headerNames;
}
bool isValid () const override;
shared_ptr<Header> createHeader () const override;
private:
string mHeaderNames;
};
bool RequireHeaderNode::isValid () const {
return !mHeaderNames.empty();
}
shared_ptr<Header> RequireHeaderNode::createHeader () const {
if (!isValid())
return nullptr;
return make_shared<RequireHeader>(mHeaderNames);
}
// -------------------------------------------------------------------------
class ListHeaderNode :
public Node,
public list<shared_ptr<HeaderNode> > {};
@ -164,67 +516,61 @@ namespace Cpim {
class MessageNode : public Node {
public:
void addHeaders (const shared_ptr<ListHeaderNode> &headers) {
mHeaders->push_back(headers);
void addMessageHeaders (const shared_ptr<ListHeaderNode> &headers) {
for (const auto &headerNode : *headers) {
mMessageHeaders.push_back(headerNode);
}
}
void addContentHeaders (const shared_ptr<ListHeaderNode> &headers) {
for (const auto &headerNode : *headers) {
mContentHeaders.push_back(headerNode);
}
}
// Warning: Call this function one time!
shared_ptr<Message> createMessage () const {
size_t size = mHeaders->size();
if (size < 2 || size > 3) { // TODO: Check that size is == 2
if (mContentHeaders.empty() || mMessageHeaders.empty()) {
lWarning() << "Bad headers lists size.";
return nullptr;
}
//TODO: Verify all headers from other namespaces
const shared_ptr<Message> message = make_shared<Message>();
// TODO: To remove
if (size == 3) {
const shared_ptr<ListHeaderNode> cpimHeaders = mHeaders->front();
if (find_if(cpimHeaders->cbegin(), cpimHeaders->cend(),
[](const shared_ptr<const HeaderNode> &headerNode) {
return Utils::iequals(headerNode->getName(), "content-type") && (ContentType(headerNode->getValue()) == ContentType::Cpim);
}) == cpimHeaders->cend()) {
lWarning() << "No MIME `Content-Type` found!";
// Add message headers.
for (const auto &headerNode : mMessageHeaders) {
string ns = "";
string::size_type n = headerNode->getName().find(".");
if (n != string::npos) {
ns = headerNode->getName().substr(0, n);
headerNode->setName(headerNode->getName().substr(n + 1));
}
const shared_ptr<const Header> header = headerNode->createHeader();
if (!header)
return nullptr;
}
// Add MIME headers.
for (const auto &headerNode : *cpimHeaders) {
const shared_ptr<const Header> header = headerNode->createHeader();
if (!header || !message->addCpimHeader(*header))
return nullptr;
}
// Add message headers.
for (const auto &headerNode : **(++mHeaders->cbegin())) {
const shared_ptr<const Header> header = headerNode->createHeader();
if (!header || !message->addMessageHeader(*header))
return nullptr;
}
}
// TODO: To remove
else {
// Add message headers.
for (const auto &headerNode : *mHeaders->front()) {
const shared_ptr<const Header> header = headerNode->createHeader();
if (!header || !message->addMessageHeader(*header))
return nullptr;
}
message->addMessageHeader(*header, ns);
}
// Add content headers.
for (const auto &headerNode : *mHeaders->back()) {
for (const auto &headerNode : mContentHeaders) {
const shared_ptr<const Header> header = headerNode->createHeader();
if (!header || !message->addContentHeader(*header))
if (!header)
return nullptr;
message->addContentHeader(*header);
}
return message;
}
private:
shared_ptr<list<shared_ptr<ListHeaderNode> > > mHeaders = make_shared<list<shared_ptr<ListHeaderNode> > >();
list<shared_ptr<HeaderNode>> mContentHeaders;
list<shared_ptr<HeaderNode>> mMessageHeaders;
};
}
@ -261,27 +607,64 @@ shared_ptr<Cpim::Message> Cpim::Parser::parseMessage (const string &input) {
typedef void (list<shared_ptr<HeaderNode> >::*pushPtr)(const shared_ptr<HeaderNode> &value);
belr::Parser<shared_ptr<Node> > parser(d->grammar);
parser.setHandler(
"Message", belr::make_fn(make_shared<MessageNode> )
)->setCollector(
"Headers", belr::make_sfn(&MessageNode::addHeaders)
);
parser.setHandler("Message", belr::make_fn(make_shared<MessageNode>))
->setCollector("Message-headers", belr::make_sfn(&MessageNode::addMessageHeaders))
->setCollector("Content-headers", belr::make_sfn(&MessageNode::addContentHeaders));
parser.setHandler(
"Headers", belr::make_fn(make_shared<ListHeaderNode> )
)->setCollector(
"Header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back))
);
parser.setHandler("Message-headers", belr::make_fn(make_shared<ListHeaderNode>))
->setCollector("Header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
->setCollector("From-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
->setCollector("To-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
->setCollector("DateTime-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
->setCollector("cc-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
->setCollector("Subject-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
->setCollector("NS-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)))
->setCollector("Require-header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)));
parser.setHandler(
"Header", belr::make_fn(make_shared<HeaderNode> )
)->setCollector(
"Header-name", belr::make_sfn(&HeaderNode::setName)
)->setCollector(
"Header-value", belr::make_sfn(&HeaderNode::setValue)
)->setCollector(
"Header-parameters", belr::make_sfn(&HeaderNode::setParameters)
);
parser.setHandler("Content-headers", belr::make_fn(make_shared<ListHeaderNode>))
->setCollector("Header", belr::make_sfn(static_cast<pushPtr>(&ListHeaderNode::push_back)));
parser.setHandler("Header", belr::make_fn(make_shared<HeaderNode>))
->setCollector("Header-name", belr::make_sfn(&HeaderNode::setName))
->setCollector("Header-value", belr::make_sfn(&HeaderNode::setValue))
->setCollector("Header-parameters", belr::make_sfn(&HeaderNode::setParameters));
parser.setHandler("From-header", belr::make_fn(make_shared<FromHeaderNode>))
->setCollector("Formal-name", belr::make_sfn(&FromHeaderNode::setFormalName))
->setCollector("URI", belr::make_sfn(&FromHeaderNode::setUri));
parser.setHandler("To-header", belr::make_fn(make_shared<ToHeaderNode>))
->setCollector("Formal-name", belr::make_sfn(&ToHeaderNode::setFormalName))
->setCollector("URI", belr::make_sfn(&ToHeaderNode::setUri));
parser.setHandler("cc-header", belr::make_fn(make_shared<CcHeaderNode>))
->setCollector("Formal-name", belr::make_sfn(&CcHeaderNode::setFormalName))
->setCollector("URI", belr::make_sfn(&CcHeaderNode::setUri));
parser.setHandler("DateTime-header", belr::make_fn(make_shared<DateTimeHeaderNode>))
->setCollector("date-fullyear", belr::make_sfn(&DateTimeHeaderNode::setYear))
->setCollector("date-month", belr::make_sfn(&DateTimeHeaderNode::setMonth))
->setCollector("date-mday", belr::make_sfn(&DateTimeHeaderNode::setMonthDay))
->setCollector("time-hour", belr::make_sfn(&DateTimeHeaderNode::setHour))
->setCollector("time-minute", belr::make_sfn(&DateTimeHeaderNode::setMinute))
->setCollector("time-second", belr::make_sfn(&DateTimeHeaderNode::setSecond))
->setCollector("time-offset", belr::make_sfn(&DateTimeHeaderNode::setOffset));
parser.setHandler("time-offset", belr::make_fn(make_shared<DateTimeOffsetNode>))
->setCollector("time-sign", belr::make_sfn(&DateTimeOffsetNode::setSign))
->setCollector("time-hour", belr::make_sfn(&DateTimeOffsetNode::setHour))
->setCollector("time-minute", belr::make_sfn(&DateTimeOffsetNode::setMinute));
parser.setHandler("Subject-header", belr::make_fn(make_shared<SubjectHeaderNode>))
->setCollector("Language-tag", belr::make_sfn(&SubjectHeaderNode::setLanguage))
->setCollector("Header-value", belr::make_sfn(&SubjectHeaderNode::setSubject));
parser.setHandler("Ns-header", belr::make_fn(make_shared<NsHeaderNode>))
->setCollector("Name-prefix", belr::make_sfn(&NsHeaderNode::setPrefixName))
->setCollector("URI", belr::make_sfn(&NsHeaderNode::setUri));
parser.setHandler("Require-header", belr::make_fn(make_shared<RequireHeaderNode>))
->setCollector("Require-header-value", belr::make_sfn(&RequireHeaderNode::setHeaderNames));
size_t parsedSize;
shared_ptr<Node> node = parser.parseInput("Message", input, &parsedSize);
@ -306,149 +689,28 @@ shared_ptr<Cpim::Message> Cpim::Parser::parseMessage (const string &input) {
// -----------------------------------------------------------------------------
shared_ptr<Cpim::Header> Cpim::Parser::cloneHeader (const Header &header) {
return HeaderNode(header).createHeader(true);
}
if (header.getName() == "From")
return FromHeaderNode(header).createHeader();
// -----------------------------------------------------------------------------
if (header.getName() == "To")
return ToHeaderNode(header).createHeader();
class EmptyObject {};
if (header.getName() == "cc")
return CcHeaderNode(header).createHeader();
static bool headerIsValid (const shared_ptr<belr::Grammar> &grammar, const string &input) {
belr::Parser<shared_ptr<EmptyObject> > parser(grammar);
parser.setHandler(
"Header", belr::make_fn(make_shared<EmptyObject> )
);
if (header.getName() == "DateTime")
return DateTimeHeaderNode(header).createHeader();
size_t parsedSize;
shared_ptr<EmptyObject> node = parser.parseInput("Header", input, &parsedSize);
return node && parsedSize == input.length();
}
if (header.getName() == "Subject")
return SubjectHeaderNode(header).createHeader();
bool Cpim::Parser::headerNameIsValid (const string &headerName) const {
L_D();
return headerIsValid(d->grammar, headerName + ": value\r\n");
}
if (header.getName() == "NS")
return NsHeaderNode(header).createHeader();
bool Cpim::Parser::headerValueIsValid (const string &headerValue) const {
L_D();
return headerIsValid(d->grammar, "key: " + headerValue + "\r\n");
}
if (header.getName() == "Require")
return RequireHeaderNode(header).createHeader();
bool Cpim::Parser::headerParameterIsValid (const string &headerParameter) const {
L_D();
return headerIsValid(d->grammar, "key:;" + headerParameter + " value\r\n");
}
// -----------------------------------------------------------------------------
static bool coreHeaderIsValid (
const shared_ptr<belr::Grammar> &grammar,
const string &headerName,
const string &headerValue,
const string &headerParams = string()
) {
const string mainRule = headerName + "-header";
belr::Parser<shared_ptr<EmptyObject> > parser(grammar);
parser.setHandler(
mainRule, belr::make_fn(make_shared<EmptyObject> )
);
const string input = headerName + ":" + headerParams + " " + headerValue;
size_t parsedSize;
shared_ptr<EmptyObject> node = parser.parseInput(mainRule, input, &parsedSize);
return node && parsedSize == input.length();
}
template<>
bool Cpim::Parser::coreHeaderIsValid<Cpim::FromHeader> (const string &headerValue) const {
L_D();
return LinphonePrivate::coreHeaderIsValid(d->grammar, "From", headerValue);
}
template<>
bool Cpim::Parser::coreHeaderIsValid<Cpim::ToHeader> (const string &headerValue) const {
L_D();
return LinphonePrivate::coreHeaderIsValid(d->grammar, "To", headerValue);
}
template<>
bool Cpim::Parser::coreHeaderIsValid<Cpim::CcHeader> (const string &headerValue) const {
L_D();
return LinphonePrivate::coreHeaderIsValid(d->grammar, "cc", headerValue);
}
template<>
bool Cpim::Parser::coreHeaderIsValid<Cpim::DateTimeHeader> (const string &headerValue) const {
static const int daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
L_D();
if (!LinphonePrivate::coreHeaderIsValid(d->grammar, "DateTime", headerValue))
return false;
// Check date.
const int year = Utils::stoi(headerValue.substr(0, 4));
const bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
const int month = Utils::stoi(headerValue.substr(5, 2));
if (month < 1 || month > 12)
return false;
const int day = Utils::stoi(headerValue.substr(8, 2));
if (day < 1 || (month == 2 && isLeapYear ? day > 29 : day > daysInMonth[month - 1]))
return false;
// Check time.
if (
Utils::stoi(headerValue.substr(11, 2)) > 24 ||
Utils::stoi(headerValue.substr(14, 2)) > 59 ||
Utils::stoi(headerValue.substr(17, 2)) > 60
)
return false;
// Check num offset.
if (headerValue.back() != 'Z') {
size_t length = headerValue.length();
if (
Utils::stoi(headerValue.substr(length - 5, 2)) > 24 ||
Utils::stoi(headerValue.substr(length - 2, 2)) > 59
)
return false;
}
return true;
}
template<>
bool Cpim::Parser::coreHeaderIsValid<Cpim::MessageIdHeader> (const string &headerValue) const {
L_D();
return LinphonePrivate::coreHeaderIsValid(d->grammar, "Message-ID", headerValue);
}
template<>
bool Cpim::Parser::coreHeaderIsValid<Cpim::SubjectHeader> (const string &headerValue) const {
L_D();
return LinphonePrivate::coreHeaderIsValid(d->grammar, "Subject", headerValue);
}
template<>
bool Cpim::Parser::coreHeaderIsValid<Cpim::NsHeader> (const string &headerValue) const {
L_D();
return LinphonePrivate::coreHeaderIsValid(d->grammar, "NS", headerValue);
}
template<>
bool Cpim::Parser::coreHeaderIsValid<Cpim::RequireHeader> (const string &headerValue) const {
L_D();
return LinphonePrivate::coreHeaderIsValid(d->grammar, "Require", headerValue);
}
// -----------------------------------------------------------------------------
bool Cpim::Parser::subjectHeaderLanguageIsValid (const string &language) const {
L_D();
return LinphonePrivate::coreHeaderIsValid(d->grammar, "Subject", "SubjectValue", ";lang=" + language);
return HeaderNode(header).createHeader();
}
LINPHONE_END_NAMESPACE

View file

@ -38,49 +38,12 @@ namespace Cpim {
std::shared_ptr<Header> cloneHeader (const Header &header);
bool headerNameIsValid (const std::string &headerName) const;
bool headerValueIsValid (const std::string &headerValue) const;
bool headerParameterIsValid (const std::string &headerParameter) const;
template<typename>
bool coreHeaderIsValid (const std::string &headerValue) const {
return false;
}
bool subjectHeaderLanguageIsValid (const std::string &language) const;
private:
Parser ();
L_DECLARE_PRIVATE(Parser);
L_DISABLE_COPY(Parser);
};
// ---------------------------------------------------------------------------
template<>
bool Parser::coreHeaderIsValid<FromHeader>(const std::string &headerValue) const;
template<>
bool Parser::coreHeaderIsValid<ToHeader>(const std::string &headerValue) const;
template<>
bool Parser::coreHeaderIsValid<CcHeader>(const std::string &headerValue) const;
template<>
bool Parser::coreHeaderIsValid<DateTimeHeader>(const std::string &headerValue) const;
template<>
bool Parser::coreHeaderIsValid<MessageIdHeader>(const std::string &headerValue) const;
template<>
bool Parser::coreHeaderIsValid<SubjectHeader>(const std::string &headerValue) const;
template<>
bool Parser::coreHeaderIsValid<NsHeader>(const std::string &headerValue) const;
template<>
bool Parser::coreHeaderIsValid<RequireHeader>(const std::string &headerValue) const;
}
LINPHONE_END_NAMESPACE

View file

@ -1,7 +1,13 @@
Message = Headers CRLF Headers CRLF [Headers CRLF]
Message = [Crappy-header CRLF] Message-headers CRLF Content-headers CRLF
Headers = *Header
Header = Header-name ":" Header-parameters SP Header-value CRLF
Crappy-header = "Content-Type: Message/CPIM" CRLF
Message-headers = 1*( Message-header CRLF )
Message-header = From-header / To-header / DateTime-header / cc-header / Subject-header / NS-header / Require-header / Header
Content-headers = 1*( Header CRLF )
Header = Header-name ":" Header-parameters SP Header-value
Header-name = [ Name-prefix "." ] Name
Name-prefix = Name
@ -25,13 +31,11 @@ To-header-value = [ Formal-name ] "<" URI ">"
DateTime-header = %d68.97.116.101.84.105.109.101 ": " DateTime-header-value
DateTime-header-value = date-time
Message-ID-header = %d77.101.115.115.97.103.101.45.73.68 ": " Token
cc-header = %d99.99 ": " cc-header-value
cc-header-value = [ Formal-name ] "<" URI ">"
Subject-header = %d83.117.98.106.101.99.116 ":" Subject-header-value
Subject-header-value = [ ";" Lang-param ] SP *HEADERCHAR
Subject-header-value = [ ";" Lang-param ] SP Header-value
NS-header = %d78.83 ": " NS-header-value
NS-header-value = [ Name-prefix SP ] "<" URI ">"
@ -136,7 +140,8 @@ time-minute = 2DIGIT
time-second = 2DIGIT
time-secfrac = "." 1*DIGIT
time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
time-sign = "+" / "-"
time-numoffset = time-sign time-hour ":" time-minute
time-offset = "Z" / time-numoffset
partial-time = time-hour ":" time-minute ":" time-second [ time-secfrac ]

View file

@ -17,11 +17,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/utils/utils.h"
#include "address/address.h"
#include "chat/chat-message/chat-message-p.h"
#include "chat/cpim/cpim.h"
#include "content/content-type.h"
#include "content/content.h"
#include "content/content-disposition.h"
#include "content/content-type.h"
#include "logger/logger.h"
#include "cpim-chat-message-modifier.h"
@ -35,25 +38,44 @@ LINPHONE_BEGIN_NAMESPACE
ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr<ChatMessage> &message, int &errorCode) {
Cpim::Message cpimMessage;
// TODO: Remove this buggy Content-Type header
Cpim::GenericHeader cpimContentTypeHeader;
cpimContentTypeHeader.setName("Content-Type");
cpimContentTypeHeader.setValue(ContentType::Cpim.asString());
cpimMessage.addCpimHeader(cpimContentTypeHeader);
// TODO: Remove this buggy Content-Type header
cpimMessage.addMessageHeader(
Cpim::FromHeader(cpimAddressUri(message->getFromAddress()), cpimAddressDisplayName(message->getFromAddress()))
);
cpimMessage.addMessageHeader(
Cpim::ToHeader(cpimAddressUri(message->getToAddress()), cpimAddressDisplayName(message->getToAddress()))
);
cpimMessage.addMessageHeader(
Cpim::DateTimeHeader(message->getTime())
);
Cpim::FromHeader cpimFromHeader;
cpimFromHeader.setValue(cpimAddressAsString(message->getFromAddress()));
cpimMessage.addMessageHeader(cpimFromHeader);
Cpim::ToHeader cpimToHeader;
cpimToHeader.setValue(cpimAddressAsString(message->getToAddress()));
cpimMessage.addMessageHeader(cpimToHeader);
char token[13];
belle_sip_random_token(token, sizeof(token));
Cpim::MessageIdHeader cpimMessageIdHeader;
cpimMessageIdHeader.setValue(token);
cpimMessage.addMessageHeader(cpimMessageIdHeader);
message->getPrivate()->setImdnMessageId(token);
if (message->getPrivate()->getPositiveDeliveryNotificationRequired()
|| message->getPrivate()->getNegativeDeliveryNotificationRequired()
|| message->getPrivate()->getDisplayNotificationRequired()
) {
const string imdnNamespace = "imdn";
cpimMessage.addMessageHeader(Cpim::NsHeader("urn:ietf:params:imdn", imdnNamespace));
char token[13];
belle_sip_random_token(token, sizeof(token));
cpimMessage.addMessageHeader(
Cpim::GenericHeader("Message-ID", token) // TODO: Replace by imdnNamespace + ".Message-ID");
);
message->getPrivate()->setImdnMessageId(token);
vector<string> dispositionNotificationValues;
if (message->getPrivate()->getPositiveDeliveryNotificationRequired())
dispositionNotificationValues.emplace_back("positive-delivery");
if (message->getPrivate()->getNegativeDeliveryNotificationRequired())
dispositionNotificationValues.emplace_back("negative-delivery");
if (message->getPrivate()->getDisplayNotificationRequired())
dispositionNotificationValues.emplace_back("display");
cpimMessage.addMessageHeader(
Cpim::GenericHeader(
imdnNamespace + ".Disposition-Notification",
Utils::join(dispositionNotificationValues, ", ")
)
);
}
const Content *content;
if (!message->getInternalContent().isEmpty()) {
@ -66,21 +88,19 @@ ChatMessageModifier::Result CpimChatMessageModifier::encode (const shared_ptr<Ch
content = message->getContents().front();
}
Cpim::GenericHeader contentTypeHeader;
contentTypeHeader.setName("Content-Type");
contentTypeHeader.setValue(content->getContentType().asString());
cpimMessage.addContentHeader(contentTypeHeader);
const string contentBody = content->getBodyAsString();
cpimMessage.setContent(contentBody);
// TODO: Remove this check because of buggy Content-Type header
if (!cpimMessage.isValid()) {
lError() << "[CPIM] Message is invalid: " << contentBody;
errorCode = 500;
return ChatMessageModifier::Result::Error;
if (content->getContentDisposition().isValid()) {
cpimMessage.addContentHeader(
Cpim::GenericHeader("Content-Disposition", content->getContentDisposition().asString())
);
}
// TODO: Remove this check because of buggy Content-Type header
cpimMessage.addContentHeader(
Cpim::GenericHeader("Content-Type", content->getContentType().asString())
);
cpimMessage.addContentHeader(
Cpim::GenericHeader("Content-Length", to_string(contentBody.size()))
);
cpimMessage.setContent(contentBody);
Content newContent;
newContent.setContentType(ContentType::Cpim);
@ -104,44 +124,69 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr<Ch
const string contentBody = content->getBodyAsString();
const shared_ptr<const Cpim::Message> cpimMessage = Cpim::Message::createFromString(contentBody);
if (!cpimMessage) {
if (!cpimMessage || !cpimMessage->getMessageHeader("From") || !cpimMessage->getMessageHeader("To")) {
lError() << "[CPIM] Message is invalid: " << contentBody;
errorCode = 500;
errorCode = 488; // Not Acceptable
return ChatMessageModifier::Result::Error;
}
Content newContent;
bool contentTypeFound = false;
Cpim::Message::HeaderList l = cpimMessage->getContentHeaders();
if (l) {
for (const auto &header : *l.get()) {
if (header->getName() == "Content-Type") {
contentTypeFound = true;
newContent.setContentType(ContentType(header->getValue()));
auto contentTypeHeader = cpimMessage->getContentHeader("Content-Type");
if (!contentTypeHeader) {
lError() << "[CPIM] No Content-type for the content of the message";
errorCode = 488; // Not Acceptable
return ChatMessageModifier::Result::Error;
}
newContent.setContentType(ContentType(contentTypeHeader->getValue()));
auto contentDispositionHeader = cpimMessage->getContentHeader("Content-Disposition");
if (contentDispositionHeader)
newContent.setContentDisposition(ContentDisposition(contentDispositionHeader->getValue()));
newContent.setBody(cpimMessage->getContent());
message->getPrivate()->setPositiveDeliveryNotificationRequired(false);
message->getPrivate()->setNegativeDeliveryNotificationRequired(false);
message->getPrivate()->setDisplayNotificationRequired(false);
string imdnNamespace = "";
auto messageHeaders = cpimMessage->getMessageHeaders();
if (messageHeaders) {
for (const auto &header : *messageHeaders.get()) {
if (header->getName() != "NS")
continue;
auto nsHeader = static_pointer_cast<const Cpim::NsHeader>(header);
if (nsHeader->getUri() == "urn:ietf:params:imdn") {
imdnNamespace = nsHeader->getPrefixName();
break;
}
}
}
if (!contentTypeFound) {
lError() << "[CPIM] No Content-type for the content of the message";
errorCode = 500;
return ChatMessageModifier::Result::Error;
}
newContent.setBody(cpimMessage->getContent());
Address cpimFromAddress;
Address cpimToAddress;
l = cpimMessage->getMessageHeaders();
if (l) {
for (const auto &header : *l.get()) {
if (header->getName() == "From")
cpimFromAddress = Address(header->getValue());
else if (header->getName() == "To")
cpimToAddress = Address(header->getValue());
else if (header->getName() == "Message-ID")
message->getPrivate()->setImdnMessageId(header->getValue());
auto fromHeader = static_pointer_cast<const Cpim::FromHeader>(cpimMessage->getMessageHeader("From"));
Address cpimFromAddress(fromHeader->getValue());
auto toHeader = static_pointer_cast<const Cpim::ToHeader>(cpimMessage->getMessageHeader("To"));
Address cpimToAddress(toHeader->getValue());
auto dateTimeHeader = static_pointer_cast<const Cpim::DateTimeHeader>(cpimMessage->getMessageHeader("DateTime"));
if (dateTimeHeader)
message->getPrivate()->setTime(dateTimeHeader->getTime());
auto messageIdHeader = cpimMessage->getMessageHeader("Message-ID"); // TODO: For compatibility, to remove
if (!imdnNamespace.empty()) {
if (!messageIdHeader)
messageIdHeader = cpimMessage->getMessageHeader("Message-ID", imdnNamespace);
auto dispositionNotificationHeader = cpimMessage->getMessageHeader("Disposition-Notification", imdnNamespace);
if (dispositionNotificationHeader) {
vector<string> values = Utils::split(dispositionNotificationHeader->getValue(), ", ");
for (const auto &value : values)
if (value == "positive-delivery")
message->getPrivate()->setPositiveDeliveryNotificationRequired(true);
else if (value == "negative-delivery")
message->getPrivate()->setNegativeDeliveryNotificationRequired(true);
else if (value == "display")
message->getPrivate()->setDisplayNotificationRequired(true);
}
}
if (messageIdHeader)
message->getPrivate()->setImdnMessageId(messageIdHeader->getValue());
// Modify the initial message since there was no error
message->setInternalContent(newContent);
@ -151,12 +196,12 @@ ChatMessageModifier::Result CpimChatMessageModifier::decode (const shared_ptr<Ch
return ChatMessageModifier::Result::Done;
}
string CpimChatMessageModifier::cpimAddressAsString (const Address &addr) const {
ostringstream os;
if (!addr.getDisplayName().empty())
os << addr.getDisplayName() << " ";
os << "<" << addr.asStringUriOnly() << ">";
return os.str();
string CpimChatMessageModifier::cpimAddressDisplayName (const Address &addr) const {
return addr.getDisplayName();
}
string CpimChatMessageModifier::cpimAddressUri (const Address &addr) const {
return addr.asStringUriOnly();
}
LINPHONE_END_NAMESPACE

View file

@ -34,7 +34,8 @@ public:
Result decode (const std::shared_ptr<ChatMessage> &message, int &errorCode) override;
private:
std::string cpimAddressAsString (const Address &addr) const;
std::string cpimAddressDisplayName (const Address &addr) const;
std::string cpimAddressUri (const Address &addr) const;
};
LINPHONE_END_NAMESPACE

View file

@ -116,7 +116,6 @@ void FileTransferChatMessageModifier::fileTransferOnProgress (
// Legacy: call back given by application level.
linphone_core_notify_file_transfer_progress_indication(message->getCore()->getCCore(), msg, content, offset, total);
}
linphone_content_unref(content);
}
static int _chat_message_on_send_body (
@ -173,7 +172,6 @@ int FileTransferChatMessageModifier::onSendBody (
// Legacy
linphone_core_notify_file_transfer_send(message->getCore()->getCCore(), msg, content, (char *)buffer, size);
}
linphone_content_unref(content);
}
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(message->getCore()->getCCore());
@ -253,12 +251,25 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, L_GET_C_BACK_PTR(message->getChatRoom()));
}
}
FileTransferContent *fileTransferContent = new FileTransferContent();
fileTransferContent->setContentType(ContentType::FileTransfer);
fileTransferContent->setFileSize(currentFileContentToTransfer->getFileSize()); // Copy file size information
message->getPrivate()->addContent(fileTransferContent);
// shall we encrypt the file
if (is_file_encryption_enabled && message->getChatRoom()) {
// temporary storage for the Content-disposition header value : use a generic filename to not leak it
// Actual filename stored in msg->file_transfer_information->name will be set in encrypted msg
// sended to the
first_part_header = "form-data; name=\"File\"; filename=\"filename.txt\"";
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb =
linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs);
if (generate_file_transfer_key_cb) {
generate_file_transfer_key_cb(imee, L_GET_C_BACK_PTR(message->getChatRoom()), L_GET_C_BACK_PTR(message));
}
} else {
// temporary storage for the Content-disposition header value
first_part_header = "form-data; name=\"File\"; filename=\"" + currentFileContentToTransfer->getFileName() + "\"";
@ -273,6 +284,8 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
// No need to add again the callback for progression, otherwise it will be called twice
first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(currentFileContentToTransfer->getFilePath().c_str(), nullptr, this);
belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler);
// Ensure the file size has been set to the correct value
fileTransferContent->setFileSize(belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh));
} else if (!currentFileContentToTransfer->isEmpty()) {
first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer(
ms_strdup(currentFileContentToTransfer->getBodyAsString().c_str()),
@ -294,34 +307,25 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
uploadFile();
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(httpRequest), BELLE_SIP_BODY_HANDLER(bh));
} else if (code == 200) { // file has been uploaded correctly, get server reply and send it
FileTransferContent *fileTransferContent = nullptr;
for (Content *c : message->getPrivate()->getContents()) {
if (c->isFileTransfer()) {
FileTransferContent *tmpContent = static_cast<FileTransferContent *>(c);
if (!tmpContent->getFileContent() && tmpContent->getSize() == 0) {
// If FileTransferContent doesn't have a FileContent yet and is empty
// It's the one we seek, otherwise it may be a previous uploaded FileTransferContent
fileTransferContent = tmpContent;
break;
}
}
}
const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
if (body && strlen(body) > 0) {
FileTransferContent *fileTransferContent = new FileTransferContent();
fileTransferContent->setContentType(ContentType::FileTransfer);
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(message->getCore()->getCCore());
bool_t is_file_encryption_enabled = FALSE;
if (imee && message->getChatRoom()) {
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
LinphoneImEncryptionEngineCbsIsEncryptionEnabledForFileTransferCb is_encryption_enabled_for_file_transfer_cb =
linphone_im_encryption_engine_cbs_get_is_encryption_enabled_for_file_transfer(imee_cbs);
if (is_encryption_enabled_for_file_transfer_cb) {
is_file_encryption_enabled = is_encryption_enabled_for_file_transfer_cb(imee, L_GET_C_BACK_PTR(message->getChatRoom()));
}
}
if (is_file_encryption_enabled && message->getChatRoom()) {
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
LinphoneImEncryptionEngineCbsGenerateFileTransferKeyCb generate_file_transfer_key_cb =
linphone_im_encryption_engine_cbs_get_generate_file_transfer_key(imee_cbs);
if (generate_file_transfer_key_cb) {
generate_file_transfer_key_cb(imee, L_GET_C_BACK_PTR(message->getChatRoom()), L_GET_C_BACK_PTR(message));
}
}
// if we have an encryption key for the file, we must insert it into the msg and restore the correct filename
const char *content_key = fileTransferContent->getFileKeyAsString();
size_t content_key_size = fileTransferContent->getFileKey().size();
if (content_key_size > 0) {
const unsigned char *contentKey = reinterpret_cast<const unsigned char *>(fileTransferContent->getFileKey().data());
size_t contentKeySize = fileTransferContent->getFileKeySize();
if (contentKeySize > 0) {
// parse the msg body
xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body);
@ -338,11 +342,11 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
xmlNodePtr fileInfoNodeChildren = cur->xmlChildrenNode;
// convert key to base64
size_t b64Size;
bctbx_base64_encode(nullptr, &b64Size, (unsigned char *)content_key, content_key_size);
bctbx_base64_encode(nullptr, &b64Size, contentKey, contentKeySize);
unsigned char *keyb64 = (unsigned char *)ms_malloc0(b64Size + 1);
int xmlStringLength;
bctbx_base64_encode(keyb64, &b64Size, (unsigned char *)content_key, content_key_size);
bctbx_base64_encode(keyb64, &b64Size, contentKey, contentKeySize);
keyb64[b64Size] = '\0'; // libxml need a null terminated string
// add the node containing the key to the file-info node
@ -381,7 +385,6 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
fileTransferContent->setFileContent(fileContent);
message->getPrivate()->removeContent(fileContent);
message->getPrivate()->addContent(fileTransferContent);
message->getPrivate()->setState(ChatMessage::State::FileTransferDone);
releaseHttpRequest();
@ -389,17 +392,44 @@ void FileTransferChatMessageModifier::processResponseFromPostFile (const belle_h
fileUploadEndBackgroundTask();
} else {
lWarning() << "Received empty response from server, file transfer failed";
FileTransferContent *fileTransferContent = nullptr;
for (Content *c : message->getPrivate()->getContents()) {
if (c->isFileTransfer()) {
fileTransferContent = static_cast<FileTransferContent *>(c);
message->getPrivate()->removeContent(fileTransferContent);
delete fileTransferContent;
break;
}
}
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
releaseHttpRequest();
fileUploadEndBackgroundTask();
}
} else if (code == 400) {
lWarning() << "Received HTTP code response " << code << " for file transfer, probably meaning file is too large";
FileTransferContent *fileTransferContent = nullptr;
for (Content *c : message->getPrivate()->getContents()) {
if (c->isFileTransfer()) {
fileTransferContent = static_cast<FileTransferContent *>(c);
message->getPrivate()->removeContent(fileTransferContent);
delete fileTransferContent;
break;
}
}
message->getPrivate()->setState(ChatMessage::State::FileTransferError);
releaseHttpRequest();
fileUploadEndBackgroundTask();
} else {
lWarning() << "Unhandled HTTP code response " << code << " for file transfer";
FileTransferContent *fileTransferContent = nullptr;
for (Content *c : message->getPrivate()->getContents()) {
if (c->isFileTransfer()) {
fileTransferContent = static_cast<FileTransferContent *>(c);
message->getPrivate()->removeContent(fileTransferContent);
delete fileTransferContent;
break;
}
}
message->getPrivate()->setState(ChatMessage::State::NotDelivered);
releaseHttpRequest();
fileUploadEndBackgroundTask();
@ -539,7 +569,6 @@ static void fillFileTransferContentInformationsFromVndGsmaRcsFtHttpXml(FileTrans
fileTransferContent->setFileSize(size);
xmlFree(fileSizeString);
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) {
xmlChar *filename = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
fileTransferContent->setFileName((char *)filename);
@ -548,6 +577,20 @@ static void fillFileTransferContentInformationsFromVndGsmaRcsFtHttpXml(FileTrans
if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) {
fileUrl = xmlGetProp(cur, (const xmlChar *)"url");
}
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-key")) {
// there is a key in the msg: file has been encrypted
// convert the key from base 64
xmlChar *keyb64 = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1);
size_t keyLength;
bctbx_base64_decode(NULL, &keyLength, (unsigned char *)keyb64, strlen((const char *)keyb64));
uint8_t *keyBuffer = (uint8_t *)malloc(keyLength);
// decode the key into local key buffer
bctbx_base64_decode(keyBuffer, &keyLength, (unsigned char *)keyb64, strlen((const char *)keyb64));
fileTransferContent->setFileKey((const char *)keyBuffer, keyLength);
// duplicate key value into the linphone content private structure
xmlFree(keyb64);
free(keyBuffer);
}
cur = cur->next;
}
@ -723,7 +766,6 @@ void FileTransferChatMessageModifier::onRecvBody (belle_sip_user_body_handler_t
// Legacy: call back given by application level
linphone_core_notify_file_transfer_recv(message->getCore()->getCCore(), msg, content, (const char *)buffer, size);
}
linphone_content_unref(content);
}
} else {
lWarning() << "File transfer decrypt failed with code " << (int)retval;
@ -764,7 +806,6 @@ void FileTransferChatMessageModifier::onRecvEnd (belle_sip_user_body_handler_t *
// Legacy: call back given by application level
linphone_core_notify_file_transfer_recv(message->getCore()->getCCore(), msg, content, nullptr, 0);
}
linphone_content_unref(content);
}
}
@ -959,7 +1000,7 @@ void FileTransferChatMessageModifier::cancelFileTransfer () {
? L_C_TO_STRING(linphone_core_get_file_transfer_server(message->getCore()->getCCore()))
: currentFileContentToTransfer->getFilePath().c_str()
);
} else {
lInfo() << "Warning: http request still running for ORPHAN msg: this is a memory leak";
}

View file

@ -74,7 +74,7 @@ private:
void releaseHttpRequest();
std::weak_ptr<ChatMessage> chatMessage;
FileContent* currentFileContentToTransfer;
FileContent* currentFileContentToTransfer = nullptr;
belle_http_request_t *httpRequest = nullptr;
belle_http_request_listener_t *httpListener = nullptr;

View file

@ -17,10 +17,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "chat/chat-message/chat-message-p.h"
#include "chat/chat-room/chat-room.h"
#include "core/core.h"
#include <algorithm>
#include "chat/chat-message/imdn-message-p.h"
#include "chat/chat-room/chat-room-p.h"
#include "core/core-p.h"
#include "logger/logger.h"
#include "xml/imdn.h"
#include "xml/linphone-imdn.h"
#include "imdn.h"
@ -30,182 +34,227 @@ using namespace std;
LINPHONE_BEGIN_NAMESPACE
const string Imdn::imdnPrefix = "/imdn:imdn";
// -----------------------------------------------------------------------------
string Imdn::createXml (const string &id, time_t time, Imdn::Type imdnType, LinphoneReason reason) {
xmlBufferPtr buf;
xmlTextWriterPtr writer;
int err;
string content;
char *datetime = nullptr;
Imdn::Imdn (ChatRoom *chatRoom) : chatRoom(chatRoom) {
chatRoom->getCore()->getPrivate()->registerListener(this);
}
// Check that the chat message has a message id.
if (id.empty())
return content;
Imdn::~Imdn () {
stopTimer();
chatRoom->getCore()->getPrivate()->unregisterListener(this);
}
buf = xmlBufferCreate();
if (buf == nullptr) {
lError() << "Error creating the XML buffer";
return content;
}
writer = xmlNewTextWriterMemory(buf, 0);
if (writer == nullptr) {
lError() << "Error creating the XML writer";
return content;
}
// -----------------------------------------------------------------------------
datetime = linphone_timestamp_to_rfc3339_string(time);
err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", nullptr);
if (err >= 0) {
err = xmlTextWriterStartElementNS(writer, nullptr, (const xmlChar *)"imdn",
(const xmlChar *)"urn:ietf:params:xml:ns:imdn");
int Imdn::getDisplayNotificationCount () const {
return static_cast<int>(displayedMessages.size());
}
// -----------------------------------------------------------------------------
void Imdn::notifyDelivery (const shared_ptr<ChatMessage> &message) {
if (find(deliveredMessages.begin(), deliveredMessages.end(), message) == deliveredMessages.end()) {
deliveredMessages.push_back(message);
startTimer();
}
if ((err >= 0) && (reason != LinphoneReasonNone)) {
err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"linphoneimdn", nullptr, (const xmlChar *)"http://www.linphone.org/xsds/imdn.xsd");
}
void Imdn::notifyDeliveryError (const shared_ptr<ChatMessage> &message, LinphoneReason reason) {
auto it = find_if(nonDeliveredMessages.begin(), nonDeliveredMessages.end(), [message](const MessageReason mr) {
return message == mr.message;
});
if (it == nonDeliveredMessages.end()) {
nonDeliveredMessages.emplace_back(message, reason);
startTimer();
}
if (err >= 0) {
err = xmlTextWriterWriteElement(writer, (const xmlChar *)"message-id", (const xmlChar *)id.c_str());
}
void Imdn::notifyDisplay (const shared_ptr<ChatMessage> &message) {
auto it = find(deliveredMessages.begin(), deliveredMessages.end(), message);
if (it != deliveredMessages.end())
deliveredMessages.erase(it);
if (find(displayedMessages.begin(), displayedMessages.end(), message) == displayedMessages.end()) {
displayedMessages.push_back(message);
startTimer();
}
if (err >= 0) {
err = xmlTextWriterWriteElement(writer, (const xmlChar *)"datetime", (const xmlChar *)datetime);
}
// -----------------------------------------------------------------------------
void Imdn::onImdnMessageDelivered (const std::shared_ptr<ImdnMessage> &message) {
// If an IMDN has been successfully delivered, remove it from the list so that
// it does not get sent again
auto context = message->getPrivate()->getContext();
for (const auto &deliveredMsg : context.deliveredMessages)
deliveredMessages.remove(deliveredMsg);
for (const auto &displayedMsg : context.displayedMessages)
displayedMessages.remove(displayedMsg);
for (const auto &nonDeliveredMsg : context.nonDeliveredMessages)
nonDeliveredMessages.remove(nonDeliveredMsg);
sentImdnMessages.remove(message);
}
// -----------------------------------------------------------------------------
void Imdn::onGlobalStateChanged (LinphoneGlobalState state) {
if (state == LinphoneGlobalShutdown) {
auto ref = chatRoom->getSharedFromThis();
deliveredMessages.clear();
displayedMessages.clear();
nonDeliveredMessages.clear();
sentImdnMessages.clear();
}
if (err >= 0) {
if (imdnType == Imdn::Type::Delivery) {
err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivery-notification");
} else {
err = xmlTextWriterStartElement(writer, (const xmlChar *)"display-notification");
}
}
void Imdn::onNetworkReachable (bool sipNetworkReachable, bool mediaNetworkReachable) {
if (sipNetworkReachable) {
// When the SIP network gets up, retry notification
sentImdnMessages.clear();
send();
}
if (err >= 0) {
err = xmlTextWriterStartElement(writer, (const xmlChar *)"status");
}
if (err >= 0) {
if (reason == LinphoneReasonNone) {
if (imdnType == Imdn::Type::Delivery) {
err = xmlTextWriterStartElement(writer, (const xmlChar *)"delivered");
} else {
err = xmlTextWriterStartElement(writer, (const xmlChar *)"displayed");
}
} else {
err = xmlTextWriterStartElement(writer, (const xmlChar *)"error");
}
}
if (err >= 0) {
// Close the "delivered", "displayed" or "error" element.
err = xmlTextWriterEndElement(writer);
}
if ((err >= 0) && (reason != LinphoneReasonNone)) {
err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"linphoneimdn", (const xmlChar *)"reason", nullptr);
if (err >= 0) {
char codestr[16];
snprintf(codestr, 16, "%d", linphone_reason_to_error_code(reason));
err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"code", (const xmlChar *)codestr);
}
if (err >= 0) {
err = xmlTextWriterWriteString(writer, (const xmlChar *)linphone_reason_to_string(reason));
}
if (err >= 0) {
err = xmlTextWriterEndElement(writer);
}
}
if (err >= 0) {
// Close the "status" element.
err = xmlTextWriterEndElement(writer);
}
if (err >= 0) {
// Close the "delivery-notification" or "display-notification" element.
err = xmlTextWriterEndElement(writer);
}
if (err >= 0) {
// Close the "imdn" element.
err = xmlTextWriterEndElement(writer);
}
if (err >= 0) {
err = xmlTextWriterEndDocument(writer);
}
if (err > 0) {
// xmlTextWriterEndDocument returns the size of the content.
content = string((char *)buf->content);
}
xmlFreeTextWriter(writer);
xmlBufferFree(buf);
}
// -----------------------------------------------------------------------------
string Imdn::createXml (const string &id, time_t timestamp, Imdn::Type imdnType, LinphoneReason reason) {
char *datetime = linphone_timestamp_to_rfc3339_string(timestamp);
Xsd::Imdn::Imdn imdn(id, datetime);
ms_free(datetime);
return content;
bool needLinphoneImdnNamespace = false;
if (imdnType == Imdn::Type::Delivery) {
Xsd::Imdn::Status status;
if (reason == LinphoneReasonNone) {
auto delivered = Xsd::Imdn::Delivered();
status.setDelivered(delivered);
} else {
auto failed = Xsd::Imdn::Failed();
status.setFailed(failed);
Xsd::LinphoneImdn::ImdnReason imdnReason(linphone_reason_to_string(reason));
imdnReason.setCode(linphone_reason_to_error_code(reason));
status.setReason(imdnReason);
needLinphoneImdnNamespace = true;
}
Xsd::Imdn::DeliveryNotification deliveryNotification(status);
imdn.setDeliveryNotification(deliveryNotification);
} else if (imdnType == Imdn::Type::Display) {
Xsd::Imdn::Status1 status;
auto displayed = Xsd::Imdn::Displayed();
status.setDisplayed(displayed);
Xsd::Imdn::DisplayNotification displayNotification(status);
imdn.setDisplayNotification(displayNotification);
}
stringstream ss;
Xsd::XmlSchema::NamespaceInfomap map;
map[""].name = "urn:ietf:params:xml:ns:imdn";
if (needLinphoneImdnNamespace)
map["imdn"].name = "http://www.linphone.org/xsds/imdn.xsd";
Xsd::Imdn::serializeImdn(ss, imdn, map, "UTF-8", Xsd::XmlSchema::Flags::dont_pretty_print);
return ss.str();
}
void Imdn::parse (const shared_ptr<ChatMessage> &chatMessage) {
xmlparsing_context_t *xmlCtx = linphone_xmlparsing_context_new();
xmlSetGenericErrorFunc(xmlCtx, linphone_xmlparsing_genericxml_error);
xmlCtx->doc = xmlReadDoc((const unsigned char *)chatMessage->getPrivate()->getText().c_str(), 0, nullptr, 0);
if (xmlCtx->doc)
parse(chatMessage, xmlCtx);
else
lWarning() << "Wrongly formatted IMDN XML: " << xmlCtx->errorBuffer;
linphone_xmlparsing_context_destroy(xmlCtx);
shared_ptr<AbstractChatRoom> cr = chatMessage->getChatRoom();
for (const auto &content : chatMessage->getPrivate()->getContents()) {
istringstream data(content->getBodyAsString());
unique_ptr<Xsd::Imdn::Imdn> imdn(Xsd::Imdn::parseImdn(data, Xsd::XmlSchema::Flags::dont_validate));
if (!imdn)
continue;
shared_ptr<ChatMessage> cm = cr->findChatMessage(imdn->getMessageId());
if (!cm) {
lWarning() << "Received IMDN for unknown message " << imdn->getMessageId();
} else {
auto policy = linphone_core_get_im_notif_policy(cr->getCore()->getCCore());
time_t imdnTime = chatMessage->getTime();
const IdentityAddress &participantAddress = chatMessage->getFromAddress().getAddressWithoutGruu();
auto &deliveryNotification = imdn->getDeliveryNotification();
auto &displayNotification = imdn->getDisplayNotification();
if (deliveryNotification.present()) {
auto &status = deliveryNotification.get().getStatus();
if (status.getDelivered().present() && linphone_im_notif_policy_get_recv_imdn_delivered(policy))
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::DeliveredToUser, imdnTime);
else if ((status.getFailed().present() || status.getError().present())
&& linphone_im_notif_policy_get_recv_imdn_delivered(policy)
)
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::NotDelivered, imdnTime);
} else if (displayNotification.present()) {
auto &status = displayNotification.get().getStatus();
if (status.getDisplayed().present() && linphone_im_notif_policy_get_recv_imdn_displayed(policy))
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::Displayed, imdnTime);
}
}
}
}
void Imdn::parse (const shared_ptr<ChatMessage> &imdnMessage, xmlparsing_context_t *xmlCtx) {
char xpathStr[MAX_XPATH_LENGTH];
char *messageIdStr = nullptr;
char *datetimeStr = nullptr;
if (linphone_create_xml_xpath_context(xmlCtx) < 0)
// -----------------------------------------------------------------------------
int Imdn::timerExpired (void *data, unsigned int revents) {
Imdn *d = reinterpret_cast<Imdn *>(data);
d->stopTimer();
d->send();
return BELLE_SIP_STOP;
}
// -----------------------------------------------------------------------------
bool Imdn::aggregationEnabled () const {
auto config = linphone_core_get_config(chatRoom->getCore()->getCCore());
bool aggregateImdn = linphone_config_get_bool(config, "misc", "aggregate_imdn", TRUE);
return (chatRoom->canHandleCpim() && aggregateImdn);
}
void Imdn::send () {
bool networkReachable = linphone_core_is_network_reachable(chatRoom->getCore()->getCCore());
if (!networkReachable)
return;
xmlXPathRegisterNs(xmlCtx->xpath_ctx, (const xmlChar *)"imdn", (const xmlChar *)"urn:ietf:params:xml:ns:imdn");
xmlXPathObjectPtr imdnObject = linphone_get_xml_xpath_object_for_node_list(xmlCtx, imdnPrefix.c_str());
if (imdnObject) {
if (imdnObject->nodesetval && (imdnObject->nodesetval->nodeNr >= 1)) {
snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:message-id", imdnPrefix.c_str());
messageIdStr = linphone_get_xml_text_content(xmlCtx, xpathStr);
snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:datetime", imdnPrefix.c_str());
datetimeStr = linphone_get_xml_text_content(xmlCtx, xpathStr);
if (!deliveredMessages.empty() || !displayedMessages.empty()) {
auto imdnMessage = chatRoom->getPrivate()->createImdnMessage(deliveredMessages, displayedMessages);
sentImdnMessages.push_back(imdnMessage);
imdnMessage->getPrivate()->send();
if (!aggregationEnabled()) {
deliveredMessages.clear();
displayedMessages.clear();
}
xmlXPathFreeObject(imdnObject);
}
if (!nonDeliveredMessages.empty()) {
auto imdnMessage = chatRoom->getPrivate()->createImdnMessage(nonDeliveredMessages);
sentImdnMessages.push_back(imdnMessage);
imdnMessage->getPrivate()->send();
if (!aggregationEnabled())
nonDeliveredMessages.clear();
}
}
void Imdn::startTimer () {
if (!aggregationEnabled()) {
// Compatibility mode for basic chat rooms, do not aggregate notifications
send();
return;
}
if (messageIdStr && datetimeStr) {
shared_ptr<AbstractChatRoom> cr = imdnMessage->getChatRoom();
shared_ptr<ChatMessage> cm = cr->findChatMessage(messageIdStr);
const IdentityAddress &participantAddress = imdnMessage->getFromAddress().getAddressWithoutGruu();
if (!cm) {
lWarning() << "Received IMDN for unknown message " << messageIdStr;
} else {
time_t imdnTime = imdnMessage->getTime();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(cr->getCore()->getCCore());
snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:delivery-notification/imdn:status", imdnPrefix.c_str());
xmlXPathObjectPtr deliveryStatusObject = linphone_get_xml_xpath_object_for_node_list(xmlCtx, xpathStr);
snprintf(xpathStr, sizeof(xpathStr), "%s[1]/imdn:display-notification/imdn:status", imdnPrefix.c_str());
xmlXPathObjectPtr displayStatusObject = linphone_get_xml_xpath_object_for_node_list(xmlCtx, xpathStr);
if (deliveryStatusObject && linphone_im_notif_policy_get_recv_imdn_delivered(policy)) {
if (deliveryStatusObject->nodesetval && (deliveryStatusObject->nodesetval->nodeNr >= 1)) {
xmlNodePtr node = deliveryStatusObject->nodesetval->nodeTab[0];
if (node->children && node->children->name) {
if (strcmp((const char *)node->children->name, "delivered") == 0) {
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::DeliveredToUser, imdnTime);
} else if (strcmp((const char *)node->children->name, "error") == 0) {
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::NotDelivered, imdnTime);
}
}
}
xmlXPathFreeObject(deliveryStatusObject);
}
if (displayStatusObject && linphone_im_notif_policy_get_recv_imdn_displayed(policy)) {
if (displayStatusObject->nodesetval && (displayStatusObject->nodesetval->nodeNr >= 1)) {
xmlNodePtr node = displayStatusObject->nodesetval->nodeTab[0];
if (node->children && node->children->name) {
if (strcmp((const char *)node->children->name, "displayed") == 0) {
cm->getPrivate()->setParticipantState(participantAddress, ChatMessage::State::Displayed, imdnTime);
}
}
}
xmlXPathFreeObject(displayStatusObject);
}
}
unsigned int duration = 500;
if (!timer)
timer = chatRoom->getCore()->getCCore()->sal->createTimer(timerExpired, this, duration, "imdn timeout");
else
belle_sip_source_set_timeout(timer, duration);
bgTask.start(chatRoom->getCore(), 1);
}
void Imdn::stopTimer () {
if (timer) {
auto core = chatRoom->getCore()->getCCore();
if (core && core->sal)
core->sal->cancelTimer(timer);
belle_sip_object_unref(timer);
timer = nullptr;
}
if (messageIdStr)
linphone_free_xml_text_content(messageIdStr);
if (datetimeStr)
linphone_free_xml_text_content(datetimeStr);
bgTask.stop();
}
LINPHONE_END_NAMESPACE

View file

@ -22,29 +22,72 @@
#include "linphone/utils/general.h"
#include "core/core-listener.h"
#include "utils/background-task.h"
#include "private.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
class ChatMessage;
class ChatRoom;
class ImdnMessage;
class Imdn {
class Imdn : public CoreListener {
public:
enum class Type {
Delivery,
Display
};
struct MessageReason {
MessageReason (const std::shared_ptr<ChatMessage> &message, LinphoneReason reason)
: message(message), reason(reason) {}
bool operator== (const MessageReason &other) const {
return (message == other.message) && (reason == other.reason);
}
const std::shared_ptr<ChatMessage> message;
LinphoneReason reason;
};
Imdn (ChatRoom *chatRoom);
~Imdn ();
int getDisplayNotificationCount () const;
void notifyDelivery (const std::shared_ptr<ChatMessage> &message);
void notifyDeliveryError (const std::shared_ptr<ChatMessage> &message, LinphoneReason reason);
void notifyDisplay (const std::shared_ptr<ChatMessage> &message);
void onImdnMessageDelivered (const std::shared_ptr<ImdnMessage> &message);
// CoreListener
void onGlobalStateChanged (LinphoneGlobalState state) override;
void onNetworkReachable (bool sipNetworkReachable, bool mediaNetworkReachable) override;
static std::string createXml (const std::string &id, time_t time, Imdn::Type imdnType, LinphoneReason reason);
static void parse (const std::shared_ptr<ChatMessage> &chatMessage);
private:
static void parse (const std::shared_ptr<ChatMessage> &chatMessage, xmlparsing_context_t *xmlCtx);
static int timerExpired (void *data, unsigned int revents);
bool aggregationEnabled () const;
void send ();
void startTimer ();
void stopTimer ();
private:
static const std::string imdnPrefix;
ChatRoom *chatRoom = nullptr;
std::list<std::shared_ptr<ChatMessage>> deliveredMessages;
std::list<std::shared_ptr<ChatMessage>> displayedMessages;
std::list<MessageReason> nonDeliveredMessages;
std::list<std::shared_ptr<ImdnMessage>> sentImdnMessages;
belle_sip_source_t *timer = nullptr;
BackgroundTask bgTask { "IMDN sending" };
};
LINPHONE_END_NAMESPACE

View file

@ -24,6 +24,7 @@
#include "chat/chat-room/chat-room-p.h"
#include "chat/notification/is-composing.h"
#include "logger/logger.h"
#include "xml/is-composing.h"
// =============================================================================
@ -42,10 +43,6 @@ struct IsRemoteComposingData {
// -----------------------------------------------------------------------------
const string IsComposing::isComposingPrefix = "/xsi:isComposing";
// -----------------------------------------------------------------------------
IsComposing::IsComposing (LinphoneCore *core, IsComposingListener *listener)
: core(core), listener(listener) {}
@ -55,72 +52,40 @@ IsComposing::~IsComposing () {
// -----------------------------------------------------------------------------
string IsComposing::marshal (bool isComposing) {
string content;
string IsComposing::createXml (bool isComposing) {
Xsd::IsComposing::IsComposing node(isComposing ? "active" : "idle");
if (isComposing)
node.setRefresh(static_cast<unsigned long long>(lp_config_get_int(core->config, "sip", "composing_refresh_timeout", defaultRefreshTimeout)));
xmlBufferPtr buf = xmlBufferCreate();
if (!buf) {
lError() << "Error creating the XML buffer";
return content;
}
xmlTextWriterPtr writer = xmlNewTextWriterMemory(buf, 0);
if (!writer) {
lError() << "Error creating the XML writer";
return content;
}
int err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", nullptr);
if (err >= 0) {
err = xmlTextWriterStartElementNS(writer, nullptr, (const xmlChar *)"isComposing",
(const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing");
}
if (err >= 0) {
err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"xsi", nullptr,
(const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance");
}
if (err >= 0) {
err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xsi", (const xmlChar *)"schemaLocation", nullptr,
(const xmlChar *)"urn:ietf:params:xml:ns:im-composing iscomposing.xsd");
}
if (err >= 0) {
err = xmlTextWriterWriteElement(writer, (const xmlChar *)"state",
isComposing ? (const xmlChar *)"active" : (const xmlChar *)"idle");
}
if ((err >= 0) && isComposing) {
int refreshTimeout = lp_config_get_int(core->config, "sip", "composing_refresh_timeout", defaultRefreshTimeout);
err = xmlTextWriterWriteElement(writer, (const xmlChar *)"refresh", (const xmlChar *)Utils::toString(refreshTimeout).c_str());
}
if (err >= 0) {
/* Close the "isComposing" element. */
err = xmlTextWriterEndElement(writer);
}
if (err >= 0) {
err = xmlTextWriterEndDocument(writer);
}
if (err > 0) {
/* xmlTextWriterEndDocument returns the size of the content. */
content = (char *)buf->content;
}
xmlFreeTextWriter(writer);
xmlBufferFree(buf);
return content;
stringstream ss;
Xsd::XmlSchema::NamespaceInfomap map;
map[""].name = "urn:ietf:params:xml:ns:im-iscomposing";
Xsd::IsComposing::serializeIsComposing(ss, node, map, "UTF-8", Xsd::XmlSchema::Flags::dont_pretty_print);
return ss.str();
}
void IsComposing::parse (const Address &remoteAddr, const string &text) {
xmlparsing_context_t *xmlCtx = linphone_xmlparsing_context_new();
xmlSetGenericErrorFunc(xmlCtx, linphone_xmlparsing_genericxml_error);
xmlCtx->doc = xmlReadDoc((const unsigned char *)text.c_str(), 0, nullptr, 0);
if (xmlCtx->doc)
parse(xmlCtx, remoteAddr);
else
lWarning() << "Wrongly formatted presence XML: " << xmlCtx->errorBuffer;
linphone_xmlparsing_context_destroy(xmlCtx);
istringstream data(text);
unique_ptr<Xsd::IsComposing::IsComposing> node(Xsd::IsComposing::parseIsComposing(data, Xsd::XmlSchema::Flags::dont_validate));
if (!node)
return;
if (node->getState() == "active") {
unsigned long long refresh = 0;
if (node->getRefresh().present())
refresh = node->getRefresh().get();
startRemoteRefreshTimer(remoteAddr.asStringUriOnly(), refresh);
listener->onIsRemoteComposingStateChanged(remoteAddr, true);
} else if (node->getState() == "idle") {
stopRemoteRefreshTimer(remoteAddr.asStringUriOnly());
listener->onIsRemoteComposingStateChanged(remoteAddr, false);
}
}
void IsComposing::startIdleTimer () {
unsigned int duration = getIdleTimerDuration();
if (!idleTimer) {
idleTimer = core->sal->create_timer(idleTimerExpired, this,
idleTimer = core->sal->createTimer(idleTimerExpired, this,
duration * 1000, "composing idle timeout");
} else {
belle_sip_source_set_timeout(idleTimer, duration * 1000);
@ -130,7 +95,7 @@ void IsComposing::startIdleTimer () {
void IsComposing::startRefreshTimer () {
unsigned int duration = getRefreshTimerDuration();
if (!refreshTimer) {
refreshTimer = core->sal->create_timer(refreshTimerExpired, this,
refreshTimer = core->sal->createTimer(refreshTimerExpired, this,
duration * 1000, "composing refresh timeout");
} else {
belle_sip_source_set_timeout(refreshTimer, duration * 1000);
@ -148,7 +113,7 @@ void IsComposing::stopTimers () {
void IsComposing::stopIdleTimer () {
if (idleTimer) {
if (core && core->sal)
core->sal->cancel_timer(idleTimer);
core->sal->cancelTimer(idleTimer);
belle_sip_object_unref(idleTimer);
idleTimer = nullptr;
}
@ -157,7 +122,7 @@ void IsComposing::stopIdleTimer () {
void IsComposing::stopRefreshTimer () {
if (refreshTimer) {
if (core && core->sal)
core->sal->cancel_timer(refreshTimer);
core->sal->cancelTimer(refreshTimer);
belle_sip_object_unref(refreshTimer);
refreshTimer = nullptr;
}
@ -186,47 +151,6 @@ unsigned int IsComposing::getRemoteRefreshTimerDuration () {
return remoteRefreshTimerDuration < 0 ? 0 : static_cast<unsigned int>(remoteRefreshTimerDuration);
}
void IsComposing::parse (xmlparsing_context_t *xmlCtx, const Address &remoteAddr) {
char xpathStr[MAX_XPATH_LENGTH];
char *stateStr = nullptr;
char *refreshStr = nullptr;
int i;
bool state = false;
if (linphone_create_xml_xpath_context(xmlCtx) < 0)
return;
xmlXPathRegisterNs(xmlCtx->xpath_ctx, (const xmlChar *)"xsi", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing");
xmlXPathObjectPtr isComposingObject = linphone_get_xml_xpath_object_for_node_list(xmlCtx, isComposingPrefix.c_str());
if (isComposingObject) {
if (isComposingObject->nodesetval) {
for (i = 1; i <= isComposingObject->nodesetval->nodeNr; i++) {
snprintf(xpathStr, sizeof(xpathStr), "%s[%i]/xsi:state", isComposingPrefix.c_str(), i);
stateStr = linphone_get_xml_text_content(xmlCtx, xpathStr);
if (!stateStr)
continue;
snprintf(xpathStr, sizeof(xpathStr), "%s[%i]/xsi:refresh", isComposingPrefix.c_str(), i);
refreshStr = linphone_get_xml_text_content(xmlCtx, xpathStr);
}
}
xmlXPathFreeObject(isComposingObject);
}
if (stateStr) {
if (strcmp(stateStr, "active") == 0) {
state = true;
startRemoteRefreshTimer(remoteAddr.asStringUriOnly(), refreshStr);
} else {
stopRemoteRefreshTimer(remoteAddr.asStringUriOnly());
}
listener->onIsRemoteComposingStateChanged(remoteAddr, state);
linphone_free_xml_text_content(stateStr);
}
if (refreshStr)
linphone_free_xml_text_content(refreshStr);
}
int IsComposing::idleTimerExpired () {
stopRefreshTimer();
stopIdleTimer();
@ -245,14 +169,14 @@ int IsComposing::remoteRefreshTimerExpired (const string &uri) {
return BELLE_SIP_STOP;
}
void IsComposing::startRemoteRefreshTimer (const string &uri, const char *refreshStr) {
void IsComposing::startRemoteRefreshTimer (const string &uri, unsigned long long refresh) {
unsigned int duration = getRemoteRefreshTimerDuration();
if (refreshStr)
duration = static_cast<unsigned int>(Utils::stoi(refreshStr));
if (refresh != 0)
duration = static_cast<unsigned int>(refresh);
auto it = remoteRefreshTimers.find(uri);
if (it == remoteRefreshTimers.end()) {
IsRemoteComposingData *data = new IsRemoteComposingData(this, uri);
belle_sip_source_t *timer = core->sal->create_timer(remoteRefreshTimerExpired, data,
belle_sip_source_t *timer = core->sal->createTimer(remoteRefreshTimerExpired, data,
duration * 1000, "composing remote refresh timeout");
pair<string, belle_sip_source_t *> p(uri, timer);
remoteRefreshTimers.insert(p);
@ -268,7 +192,7 @@ void IsComposing::stopAllRemoteRefreshTimers () {
unordered_map<string, belle_sip_source_t *>::iterator IsComposing::stopRemoteRefreshTimer (const unordered_map<string, belle_sip_source_t *>::const_iterator it) {
belle_sip_source_t *timer = it->second;
if (core && core->sal) {
core->sal->cancel_timer(timer);
core->sal->cancelTimer(timer);
delete reinterpret_cast<IsRemoteComposingData *>(belle_sip_source_get_user_data(timer));
}
belle_sip_object_unref(timer);

View file

@ -38,7 +38,7 @@ public:
IsComposing (LinphoneCore *core, IsComposingListener *listener);
~IsComposing ();
std::string marshal (bool isComposing);
std::string createXml (bool isComposing);
void parse (const Address &remoteAddr, const std::string &content);
void startIdleTimer ();
void startRefreshTimer ();
@ -51,11 +51,10 @@ private:
unsigned int getIdleTimerDuration ();
unsigned int getRefreshTimerDuration ();
unsigned int getRemoteRefreshTimerDuration ();
void parse (xmlparsing_context_t *xmlCtx, const Address &remoteAddr);
int idleTimerExpired ();
int refreshTimerExpired ();
int remoteRefreshTimerExpired (const std::string &uri);
void startRemoteRefreshTimer (const std::string &uri, const char *refreshStr);
void startRemoteRefreshTimer (const std::string &uri, unsigned long long refresh);
void stopAllRemoteRefreshTimers ();
std::unordered_map<std::string, belle_sip_source_t *>::iterator stopRemoteRefreshTimer (const std::unordered_map<std::string, belle_sip_source_t *>::const_iterator it);
@ -67,7 +66,6 @@ private:
static const int defaultIdleTimeout = 15;
static const int defaultRefreshTimeout = 60;
static const int defaultRemoteRefreshTimeout = 120;
static const std::string isComposingPrefix;
LinphoneCore *core = nullptr;
IsComposingListener *listener = nullptr;

View file

@ -209,7 +209,7 @@ void RemoteConferenceEventHandlerPrivate::subscribe () {
}
lev = linphone_event_ref(linphone_core_create_subscribe(conf->getCore()->getCCore(), lAddr, "conference", 600));
lev->op->set_from(chatRoomId.getLocalAddress().asString().c_str());
lev->op->setFrom(chatRoomId.getLocalAddress().asString().c_str());
const string &lastNotifyStr = Utils::toString(lastNotify);
linphone_event_add_custom_header(lev, "Last-Notify-Version", lastNotifyStr.c_str());
linphone_address_unref(lAddr);

View file

@ -107,7 +107,7 @@ void RemoteConferenceListEventHandler::subscribe () {
lev = linphone_event_ref(linphone_core_create_subscribe(lc, rlsAddr, "conference", 600));
char *from = linphone_address_as_string(linphone_proxy_config_get_contact(linphone_core_get_default_proxy_config(getCore()->getCCore())));
lev->op->set_from(from);
lev->op->setFrom(from);
bctbx_free(from);
linphone_address_unref(rlsAddr);
linphone_event_set_internal(lev, TRUE);

View file

@ -55,6 +55,7 @@ public:
virtual void onInfoReceived (const std::shared_ptr<CallSession> &session, const LinphoneInfoMessage *im) {}
virtual void onNoMediaTimeoutCheck (const std::shared_ptr<CallSession> &session, bool oneSecondElapsed) {}
virtual void onTmmbrReceived (const std::shared_ptr<CallSession> &session, int streamIndex, int tmmbr) {}
virtual void onSnapshotTaken(const std::shared_ptr<CallSession> &session, const char *file_path) {}
virtual void onEncryptionChanged (const std::shared_ptr<CallSession> &session, bool activated, const std::string &authToken) {}
@ -80,6 +81,7 @@ public:
virtual bool isPlayingRingbackTone (const std::shared_ptr<CallSession> &session) { return false; }
virtual void onRealTimeTextCharacterReceived (const std::shared_ptr<CallSession> &session, RealtimeTextReceivedCharacter *data) {}
};
LINPHONE_END_NAMESPACE

View file

@ -50,13 +50,13 @@ int CallSessionPrivate::computeDuration () const {
* end apparently does not support. This features are: privacy, video...
*/
void CallSessionPrivate::initializeParamsAccordingToIncomingCallParams () {
currentParams->setPrivacy((LinphonePrivacyMask)op->get_privacy());
currentParams->setPrivacy((LinphonePrivacyMask)op->getPrivacy());
}
void CallSessionPrivate::notifyReferState () {
SalCallOp *refererOp = referer->getPrivate()->getOp();
if (refererOp)
refererOp->notify_refer_state(op);
refererOp->notifyReferState(op);
}
void CallSessionPrivate::setState (CallSession::State newState, const string &message) {
@ -177,10 +177,10 @@ bool CallSessionPrivate::startPing () {
pingReplied = false;
pingOp = new SalOp(q->getCore()->getCCore()->sal);
if (direction == LinphoneCallIncoming) {
const char *from = pingOp->get_from();
const char *to = pingOp->get_to();
const char *from = pingOp->getFrom();
const char *to = pingOp->getTo();
linphone_configure_op(q->getCore()->getCCore(), pingOp, log->from, nullptr, false);
pingOp->set_route(op->get_network_origin());
pingOp->setRoute(op->getNetworkOrigin());
pingOp->ping(from, to);
} else if (direction == LinphoneCallOutgoing) {
char *from = linphone_address_as_string(log->from);
@ -189,7 +189,7 @@ bool CallSessionPrivate::startPing () {
ms_free(from);
ms_free(to);
}
pingOp->set_user_pointer(this);
pingOp->setUserPointer(this);
return true;
}
return false;
@ -230,7 +230,7 @@ void CallSessionPrivate::accepted () {
default:
break;
}
currentParams->setPrivacy((LinphonePrivacyMask)op->get_privacy());
currentParams->setPrivacy((LinphonePrivacyMask)op->getPrivacy());
}
void CallSessionPrivate::ackBeingSent (LinphoneHeaders *headers) {
@ -254,12 +254,12 @@ void CallSessionPrivate::cancelDone () {
bool CallSessionPrivate::failure () {
L_Q();
const SalErrorInfo *ei = op->get_error_info();
const SalErrorInfo *ei = op->getErrorInfo();
switch (ei->reason) {
case SalReasonRedirect:
if ((state == CallSession::State::OutgoingInit) || (state == CallSession::State::OutgoingProgress)
|| (state == CallSession::State::OutgoingRinging) /* Push notification case */ || (state == CallSession::State::OutgoingEarlyMedia)) {
const SalAddress *redirectionTo = op->get_remote_contact_address();
const SalAddress *redirectionTo = op->getRemoteContactAddress();
if (redirectionTo) {
char *url = sal_address_as_string(redirectionTo);
lWarning() << "Redirecting CallSession [" << q << "] to " << url;
@ -312,7 +312,7 @@ bool CallSessionPrivate::failure () {
void CallSessionPrivate::infoReceived (SalBodyHandler *bodyHandler) {
L_Q();
LinphoneInfoMessage *info = linphone_core_create_info_message(q->getCore()->getCCore());
linphone_info_message_set_headers(info, op->get_recv_custom_header());
linphone_info_message_set_headers(info, op->getRecvCustomHeaders());
if (bodyHandler) {
LinphoneContent *content = linphone_content_from_sal_body_handler(bodyHandler);
linphone_info_message_set_content(info, content);
@ -344,7 +344,7 @@ void CallSessionPrivate::referred (const Address &referToAddr) {
void CallSessionPrivate::remoteRinging () {
L_Q();
/* Set privacy */
currentParams->setPrivacy((LinphonePrivacyMask)op->get_privacy());
currentParams->setPrivacy((LinphonePrivacyMask)op->getPrivacy());
if (listener)
listener->onStartRinging(q->getSharedFromThis());
lInfo() << "Remote ringing...";
@ -356,12 +356,12 @@ void CallSessionPrivate::replaceOp (SalCallOp *newOp) {
SalCallOp *oldOp = op;
CallSession::State oldState = state;
op = newOp;
op->set_user_pointer(q);
op->set_local_media_description(oldOp->get_local_media_description());
op->setUserPointer(q);
op->setLocalMediaDescription(oldOp->getLocalMediaDescription());
switch (state) {
case CallSession::State::IncomingEarlyMedia:
case CallSession::State::IncomingReceived:
op->notify_ringing((state == CallSession::State::IncomingEarlyMedia) ? true : false);
op->notifyRinging((state == CallSession::State::IncomingEarlyMedia) ? true : false);
break;
case CallSession::State::Connected:
case CallSession::State::StreamsRunning:
@ -374,17 +374,17 @@ void CallSessionPrivate::replaceOp (SalCallOp *newOp) {
switch (oldState) {
case CallSession::State::IncomingEarlyMedia:
case CallSession::State::IncomingReceived:
oldOp->set_user_pointer(nullptr); // In order for the call session to not get terminated by terminating this op
oldOp->setUserPointer(nullptr); // In order for the call session to not get terminated by terminating this op
// Do not terminate a forked INVITE
if (op->get_replaces())
if (op->getReplaces())
oldOp->terminate();
else
oldOp->kill_dialog();
oldOp->killDialog();
break;
case CallSession::State::Connected:
case CallSession::State::StreamsRunning:
oldOp->terminate();
oldOp->kill_dialog();
oldOp->killDialog();
break;
default:
break;
@ -401,7 +401,7 @@ void CallSessionPrivate::terminated () {
return;
case CallSession::State::IncomingReceived:
case CallSession::State::IncomingEarlyMedia:
if (!op->get_reason_error_info()->protocol || strcmp(op->get_reason_error_info()->protocol, "") == 0) {
if (!op->getReasonErrorInfo()->protocol || strcmp(op->getReasonErrorInfo()->protocol, "") == 0) {
linphone_error_info_set(ei, nullptr, LinphoneReasonNotAnswered, 0, "Incoming call cancelled", nullptr);
nonOpError = true;
}
@ -447,7 +447,7 @@ void CallSessionPrivate::updated (bool isUpdate) {
case CallSession::State::Pausing:
case CallSession::State::Resuming:
sal_error_info_set(&sei, SalReasonInternalError, "SIP", 0, nullptr, nullptr);
op->decline_with_error_info(&sei, nullptr);
op->declineWithErrorInfo(&sei, nullptr);
BCTBX_NO_BREAK; /* no break */
case CallSession::State::Idle:
case CallSession::State::OutgoingInit:
@ -501,7 +501,7 @@ void CallSessionPrivate::accept (const CallSessionParams *csp) {
if (csp)
setParams(new CallSessionParams(*csp));
if (params)
op->set_sent_custom_header(params->getPrivate()->getCustomHeaders());
op->setSentCustomHeaders(params->getPrivate()->getCustomHeaders());
op->accept();
if (listener)
@ -527,9 +527,9 @@ LinphoneStatus CallSessionPrivate::checkForAcceptation () {
listener->onCheckForAcceptation(q->getSharedFromThis());
/* Check if this call is supposed to replace an already running one */
SalOp *replaced = op->get_replaces();
SalOp *replaced = op->getReplaces();
if (replaced) {
CallSession *session = reinterpret_cast<CallSession *>(replaced->get_user_pointer());
CallSession *session = reinterpret_cast<CallSession *>(replaced->getUserPointer());
if (session) {
lInfo() << "CallSession " << q << " replaces CallSession " << session << ". This last one is going to be terminated automatically";
session->terminate();
@ -543,8 +543,8 @@ void CallSessionPrivate::handleIncomingReceivedStateInIncomingNotification () {
/* Try to be best-effort in giving real local or routable contact address for 100Rel case */
setContactOp();
if (notifyRinging)
op->notify_ringing(false);
if (op->get_replaces() && lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "auto_answer_replacing_calls", 1))
op->notifyRinging(false);
if (op->getReplaces() && lp_config_get_int(linphone_core_get_config(q->getCore()->getCCore()), "sip", "auto_answer_replacing_calls", 1))
q->accept();
}
@ -647,9 +647,9 @@ LinphoneStatus CallSessionPrivate::startUpdate (const string &subject) {
}
if (destProxy && destProxy->op) {
/* Give a chance to update the contact address if connectivity has changed */
op->set_contact_address(destProxy->op->get_contact_address());
op->setContactAddress(destProxy->op->getContactAddress());
} else
op->set_contact_address(nullptr);
op->setContactAddress(nullptr);
return op->update(newSubject.c_str(), q->getParams()->getPrivate()->getNoUserConsent());
}
@ -703,7 +703,7 @@ void CallSessionPrivate::setContactOp () {
for (auto it = contactParams.begin(); it != contactParams.end(); it++)
linphone_address_set_param(contact, it->first.c_str(), it->second.empty() ? nullptr : it->second.c_str());
salAddress = const_cast<SalAddress *>(L_GET_PRIVATE_FROM_C_OBJECT(contact)->getInternalAddress());
op->set_contact_address(salAddress);
op->setContactAddress(salAddress);
linphone_address_unref(contact);
}
}
@ -737,12 +737,12 @@ void CallSessionPrivate::createOpTo (const LinphoneAddress *to) {
if (op)
op->release();
op = new SalCallOp(q->getCore()->getCCore()->sal);
op->set_user_pointer(q);
op->setUserPointer(q);
if (params->getPrivate()->getReferer())
op->set_referer(params->getPrivate()->getReferer()->getPrivate()->getOp());
op->setReferrer(params->getPrivate()->getReferer()->getPrivate()->getOp());
linphone_configure_op(q->getCore()->getCCore(), op, to, q->getParams()->getPrivate()->getCustomHeaders(), false);
if (q->getParams()->getPrivacy() != LinphonePrivacyDefault)
op->set_privacy((SalPrivacyMask)q->getParams()->getPrivacy());
op->setPrivacy((SalPrivacyMask)q->getParams()->getPrivacy());
/* else privacy might be set by proxy */
}
@ -751,13 +751,13 @@ void CallSessionPrivate::createOpTo (const LinphoneAddress *to) {
LinphoneAddress * CallSessionPrivate::getFixedContact () const {
L_Q();
LinphoneAddress *result = nullptr;
if (op && op->get_contact_address()) {
if (op && op->getContactAddress()) {
/* If already choosed, don't change it */
return nullptr;
} else if (pingOp && pingOp->get_contact_address()) {
} else if (pingOp && pingOp->getContactAddress()) {
/* If the ping OPTIONS request succeeded use the contact guessed from the received, rport */
lInfo() << "Contact has been fixed using OPTIONS";
char *addr = sal_address_as_string(pingOp->get_contact_address());
char *addr = sal_address_as_string(pingOp->getContactAddress());
result = linphone_address_new(addr);
ms_free(addr);
} else if (destProxy && destProxy->op && linphone_proxy_config_get_contact(destProxy)) {
@ -786,12 +786,12 @@ void CallSessionPrivate::reinviteToRecoverFromConnectionLoss () {
void CallSessionPrivate::repairByInviteWithReplaces () {
L_Q();
const char *callId = op->get_call_id();
const char *fromTag = op->get_local_tag();
const char *toTag = op->get_remote_tag();
op->kill_dialog();
const char *callId = op->getCallId();
const char *fromTag = op->getLocalTag();
const char *toTag = op->getRemoteTag();
op->killDialog();
createOp();
op->set_replaces(callId, fromTag, toTag);
op->setReplaces(callId, fromTag, toTag);
q->startInvite(nullptr);
}
@ -819,9 +819,9 @@ void CallSessionPrivate::repairIfBroken () {
switch (state) {
case CallSession::State::Updating:
case CallSession::State::Pausing:
if (op->dialog_request_pending()) {
if (op->dialogRequestPending()) {
// Need to cancel first re-INVITE as described in section 5.5 of RFC 6141
if (op->cancel_invite() == 0){
if (op->cancelInvite() == 0){
reinviteOnCancelResponseRequested = true;
}
}
@ -829,19 +829,19 @@ void CallSessionPrivate::repairIfBroken () {
case CallSession::State::StreamsRunning:
case CallSession::State::Paused:
case CallSession::State::PausedByRemote:
if (!op->dialog_request_pending())
if (!op->dialogRequestPending())
reinviteToRecoverFromConnectionLoss();
break;
case CallSession::State::UpdatedByRemote:
if (op->dialog_request_pending()) {
if (op->dialogRequestPending()) {
sal_error_info_set(&sei, SalReasonServiceUnavailable, "SIP", 0, nullptr, nullptr);
op->decline_with_error_info(&sei, nullptr);
op->declineWithErrorInfo(&sei, nullptr);
}
reinviteToRecoverFromConnectionLoss();
break;
case CallSession::State::OutgoingInit:
case CallSession::State::OutgoingProgress:
if (op->cancel_invite() == 0){
if (op->cancelInvite() == 0){
reinviteOnCancelResponseRequested = true;
}
break;
@ -931,10 +931,13 @@ void CallSession::configure (LinphoneCallDir direction, LinphoneProxyConfig *cfg
if (op) {
/* We already have an op for incoming calls */
d->op = op;
d->op->set_user_pointer(this);
op->enable_cnx_ip_to_0000_if_sendonly(!!lp_config_get_default_int(linphone_core_get_config(getCore()->getCCore()),
"sip", "cnx_ip_to_0000_if_sendonly_enabled", 0));
d->log->call_id = ms_strdup(op->get_call_id()); /* Must be known at that time */
d->op->setUserPointer(this);
op->enableCnxIpTo0000IfSendOnly(
!!lp_config_get_default_int(
linphone_core_get_config(getCore()->getCCore()), "sip", "cnx_ip_to_0000_if_sendonly_enabled", 0
)
);
d->log->call_id = ms_strdup(op->getCallId()); /* Must be known at that time */
}
if (direction == LinphoneCallOutgoing) {
@ -968,7 +971,7 @@ LinphoneStatus CallSession::decline (const LinphoneErrorInfo *ei) {
}
if (ei) {
linphone_error_info_to_sal(ei, &sei);
d->op->decline_with_error_info(&sei , nullptr);
d->op->declineWithErrorInfo(&sei , nullptr);
} else
d->op->decline(SalReasonDeclined, nullptr);
sal_error_info_reset(&sei);
@ -1053,7 +1056,7 @@ LinphoneStatus CallSession::redirect (const Address &redirectAddr) {
SalErrorInfo sei;
memset(&sei, 0, sizeof(sei));
sal_error_info_set(&sei, SalReasonRedirect, "SIP", 0, nullptr, nullptr);
d->op->decline_with_error_info(&sei, redirectAddr.getPrivate()->getInternalAddress());
d->op->declineWithErrorInfo(&sei, redirectAddr.getPrivate()->getInternalAddress());
linphone_error_info_set(d->ei, nullptr, LinphoneReasonMovedPermanently, 302, "Call redirected", nullptr);
d->nonOpError = true;
d->terminate();
@ -1096,7 +1099,7 @@ int CallSession::startInvite (const Address *destination, const string &subject,
/* Take a ref because sal_call() may destroy the CallSession if no SIP transport is available */
shared_ptr<CallSession> ref = getSharedFromThis();
if (content)
d->op->set_local_body(*content);
d->op->setLocalBody(*content);
int result = d->op->call(from, destinationStr.c_str(), subject.empty() ? nullptr : subject.c_str());
ms_free(from);
if (result < 0) {
@ -1106,7 +1109,7 @@ int CallSession::startInvite (const Address *destination, const string &subject,
d->setState(CallSession::State::Error, "Call failed");
}
} else {
d->log->call_id = ms_strdup(d->op->get_call_id()); /* Must be known at that time */
d->log->call_id = ms_strdup(d->op->getCallId()); /* Must be known at that time */
d->setState(CallSession::State::OutgoingProgress, "Outgoing call in progress");
}
return result;
@ -1134,7 +1137,7 @@ LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) {
default:
if (ei) {
linphone_error_info_to_sal(ei, &sei);
d->op->terminate_with_error(&sei);
d->op->terminate(&sei);
sal_error_info_reset(&sei);
} else
d->op->terminate();
@ -1147,7 +1150,7 @@ LinphoneStatus CallSession::terminate (const LinphoneErrorInfo *ei) {
LinphoneStatus CallSession::transfer (const shared_ptr<CallSession> &dest) {
L_D();
int result = d->op->refer_with_replaces(dest->getPrivate()->op);
int result = d->op->referWithReplaces(dest->getPrivate()->op);
d->setTransferState(CallSession::State::OutgoingInit);
return result;
}
@ -1175,7 +1178,7 @@ LinphoneStatus CallSession::update (const CallSessionParams *csp, const string &
lWarning() << "CallSession::update() is given the current params, this is probably not what you intend to do!";
if (csp)
d->setParams(new CallSessionParams(*csp));
d->op->set_local_body(content ? *content : Content());
d->op->setLocalBody(content ? *content : Content());
LinphoneStatus result = d->startUpdate(subject);
if (result && (d->state != initialState)) {
/* Restore initial state */
@ -1194,7 +1197,7 @@ LinphoneCallDir CallSession::getDirection () const {
const Address& CallSession::getDiversionAddress () const {
L_D();
if (d->op) {
char *addrStr = sal_address_as_string(d->op->get_diversion_address());
char *addrStr = sal_address_as_string(d->op->getDiversionAddress());
d->diversionAddress = Address(addrStr);
bctbx_free(addrStr);
} else {
@ -1257,7 +1260,7 @@ string CallSession::getRemoteContact () const {
L_D();
if (d->op) {
/* sal_op_get_remote_contact preserves header params */
return d->op->get_remote_contact();
return d->op->getRemoteContact();
}
return string();
}
@ -1267,7 +1270,7 @@ const Address *CallSession::getRemoteContactAddress () const {
if (!d->op) {
return nullptr;
}
char *addrStr = sal_address_as_string(d->op->get_remote_contact_address());
char *addrStr = sal_address_as_string(d->op->getRemoteContactAddress());
d->remoteContactAddress = Address(addrStr);
bctbx_free(addrStr);
return &d->remoteContactAddress;
@ -1276,7 +1279,7 @@ const Address *CallSession::getRemoteContactAddress () const {
const CallSessionParams * CallSession::getRemoteParams () {
L_D();
if (d->op){
const SalCustomHeader *ch = d->op->get_recv_custom_header();
const SalCustomHeader *ch = d->op->getRecvCustomHeaders();
if (ch) {
/* Instanciate a remote_params only if a SIP message was received before (custom headers indicates this) */
if (!d->remoteParams)
@ -1300,7 +1303,7 @@ CallSession::State CallSession::getPreviousState () const {
const Address& CallSession::getToAddress () const {
L_D();
d->toAddress = Address(d->op->get_to());
d->toAddress = Address(d->op->getTo());
return d->toAddress;
}
@ -1316,24 +1319,24 @@ shared_ptr<CallSession> CallSession::getTransferTarget () const {
string CallSession::getToHeader (const string &name) const {
L_D();
return L_C_TO_STRING(sal_custom_header_find(d->op->get_recv_custom_header(), name.c_str()));
return L_C_TO_STRING(sal_custom_header_find(d->op->getRecvCustomHeaders(), name.c_str()));
}
// -----------------------------------------------------------------------------
string CallSession::getRemoteUserAgent () const {
L_D();
if (d->op && d->op->get_remote_ua())
return d->op->get_remote_ua();
if (d->op && d->op->getRemoteUserAgent())
return d->op->getRemoteUserAgent();
return string();
}
shared_ptr<CallSession> CallSession::getReplacedCallSession () const {
L_D();
SalOp *replacedOp = d->op->get_replaces();
SalOp *replacedOp = d->op->getReplaces();
if (!replacedOp)
return nullptr;
return reinterpret_cast<CallSession *>(replacedOp->get_user_pointer())->getSharedFromThis();
return reinterpret_cast<CallSession *>(replacedOp->getUserPointer())->getSharedFromThis();
}
CallSessionParams * CallSession::getCurrentParams () const {

View file

@ -106,6 +106,9 @@ public:
// CoreListener
void onNetworkReachable (bool sipNetworkReachable, bool mediaNetworkReachable) override;
// Call listener
void snapshotTakenCb(void *userdata, struct _MSFilter *f, unsigned int id, void *arg);
private:
static OrtpJitterBufferAlgorithm jitterBufferNameToAlgo (const std::string &name);

Some files were not shown because too many files have changed in this diff Show more