Merge branch 'dev_refactor_cpp'

This commit is contained in:
Ghislain MARY 2018-06-26 14:12:27 +02:00
commit 81688335c6
916 changed files with 113612 additions and 114940 deletions

View file

@ -35,24 +35,23 @@ string(REGEX REPLACE "([a-zA-Z_]+)\\.po" "\\1" LINPHONE_ALL_LANGS_LIST "${LINPHO
string(REPLACE ";" " " LINPHONE_ALL_LANGS "${LINPHONE_ALL_LANGS_LIST}")
include(CMakeDependentOption)
include(cmake/Tools.cmake)
option(ENABLE_SHARED "Build shared library." YES)
option(ENABLE_STATIC "Build static library." YES)
option(ENABLE_CONSOLE_UI "Turn on or off compilation of console interface." YES)
option(ENABLE_CSHARP_WRAPPER "Build the C# wrapper for Liblinphone." OFF)
option(ENABLE_JAVA_WRAPPER "Build the Java wrapper for Liblinphone." OFF)
option(ENABLE_CXX_WRAPPER "Build the C++ wrapper for Liblinphone." YES)
option(ENABLE_DAEMON "Enable the linphone daemon interface." YES)
option(ENABLE_DATE "Use build date in internal version number." NO)
option(ENABLE_DEBUG_LOGS "Turn on or off debug level logs." NO)
option(ENABLE_DOC "Enable documentation generation with Doxygen." YES)
option(ENABLE_GTK_UI "Turn on or off compilation of gtk interface." NO)
option(ENABLE_DOC "Enable API documentation generation." NO)
option(ENABLE_JAVADOC "Add a target to generate documentation for Java API" NO)
option(ENABLE_LDAP "Enable LDAP support." NO)
option(ENABLE_NLS "Build with internationalisation support" YES)
option(ENABLE_RELATIVE_PREFIX "Find resources relatively to the installation directory." NO)
option(ENABLE_ROOTCA_DOWNLOAD "Download rootca.pem at build time." YES)
option(ENABLE_SOCI_STORAGE "Turn on compilation soci storage, for messages, contacts, history" YES)
option(ENABLE_SQLITE_STORAGE "Turn on compilation sqlite storage, for messages, contacts, history" YES)
option(ENABLE_STRICT "Build with strict compile options." YES)
option(ENABLE_TOOLS "Turn on or off compilation of tools." YES)
@ -66,14 +65,16 @@ option(ENABLE_VIDEO "Build with video support." YES)
cmake_dependent_option(ENABLE_LIME "Enable Instant Messaging Encryption." YES "ENABLE_SQLITE_STORAGE" NO)
cmake_dependent_option(ENABLE_NOTIFY "Enable libnotify support." YES "ENABLE_GTK_UI;NOT APPLE" NO)
cmake_dependent_option(ENABLE_ASSISTANT "Turn on assistant compiling." YES "ENABLE_GTK_UI" NO)
cmake_dependent_option(ENABLE_SPHINX_DOC "Turn on the generation of the multi-language API documentation based on Sphinx." NO "ENABLE_DOC" NO)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS NO)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DNDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions("-DDEBUG")
endif()
if(ENABLE_STATIC)
set(LINPHONE_LIBS_FOR_TOOLS linphone-static)
@ -89,6 +90,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(CheckSymbolExists)
include(CMakePushCheckState)
include(GNUInstallDirs)
include(CheckCXXCompilerFlag)
if(NOT CMAKE_INSTALL_RPATH AND CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR})
@ -132,6 +134,7 @@ else()
find_package(Belr REQUIRED)
endif()
find_package(XML2 REQUIRED)
find_package(LibXsd REQUIRED)
find_package(Soci)
find_package(ZLIB)
if(ENABLE_TUNNEL)
@ -157,32 +160,9 @@ if(ENABLE_NOTIFY)
set(ENABLE_NOTIFY OFF CACHE BOOL "Enable libnotify support." FORCE)
endif()
endif()
if(ENABLE_GTK_UI)
if(WIN32)
set(GTK2_ADDITIONAL_SUFFIXES "../lib/glib-2.0/include" "../lib/gtk-2.0/include")
endif()
find_package(GTK2 2.18 REQUIRED gtk)
if(ENABLE_ASSISTANT AND GTK2_VERSION VERSION_LESS 2.22)
message(WARNING "You need at least GTK 2.22 to enable the assistant")
set(ENABLE_ASSISTANT OFF CACHE BOOL "Turn on assistant compiling." FORCE)
endif()
if(APPLE)
find_package(GtkMacIntegration)
if(GTKMACINTEGRATION_FOUND)
set(HAVE_GTK_OSX 1)
add_definitions("${GTKMACINTEGRATION_CPPFLAGS}")
else()
message(WARNING "gtk-mac-integration not found. Please install gtk-osx-application package.")
endif()
endif()
endif()
if(ENABLE_ASSISTANT)
set(BUILD_WIZARD 1)
endif()
if(ENABLE_NLS)
find_package(Gettext REQUIRED)
find_package(Intl REQUIRED)
endif()
if(ENABLE_LIME)
#bzrtp is only required for LIME
if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS)
@ -192,8 +172,15 @@ if(ENABLE_LIME)
endif()
set(HAVE_LIME 1)
endif()
if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_SPHINX_DOC)
if(ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER OR ENABLE_DOC)
find_package(PythonInterp REQUIRED)
check_python_module(pystache)
check_python_module(six)
if(ENABLE_DOC)
check_python_module(sphinx)
check_python_module(javasphinx)
check_python_module(sphinx_csharp)
endif()
endif()
if(UNIX AND NOT APPLE)
@ -201,9 +188,22 @@ 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++")
set(LINPHONE_LDFLAGS "${LINPHONE_LDFLAGS} -stdlib=libc++")
endif()
# include_directories must be called only UNDER THIS LINE in order to use our
@ -254,7 +254,6 @@ if(MSVC)
include_directories(${MSVC_INCLUDE_DIR})
endif()
add_definitions("-DLINPHONE_EXPORTS")
set(LINPHONE_CPPFLAGS ${BELCARD_CPPFLAGS} ${BELLESIP_CPPFLAGS} ${MEDIASTREAMER2_CPPFLAGS} ${BCTOOLBOX_CPPFLAGS} ${BELR_CPPFLAGS})
if(ENABLE_STATIC)
list(APPEND LINPHONE_CPPFLAGS "-DLINPHONE_STATIC")
@ -268,6 +267,11 @@ if(ENABLE_DEBUG_LOGS)
add_definitions("-DDEBUG_LOGS")
endif()
# Enable stdint.h limit macros on C++ files. (Windows only.)
if(MSVC)
add_definitions("-D__STDC_LIMIT_MACROS")
endif()
set(STRICT_OPTIONS_CPP )
set(STRICT_OPTIONS_C )
set(STRICT_OPTIONS_CXX )
@ -279,7 +283,26 @@ if(MSVC)
list(APPEND STRICT_OPTIONS_CPP "/WX")
endif()
else()
list(APPEND STRICT_OPTIONS_CPP "-Wall" "-Wuninitialized" "-Wno-error=deprecated-declarations")
list(APPEND STRICT_OPTIONS_CPP
"-Wall"
"-Wcast-align"
"-Wconversion"
"-Werror=return-type"
"-Wfloat-equal"
"-Winit-self"
"-Wno-error=deprecated-declarations"
"-Wpointer-arith"
"-Wuninitialized"
"-Wunused"
)
list(APPEND STRICT_OPTIONS_CXX
"-Wnon-virtual-dtor"
"-Woverloaded-virtual"
)
CHECK_CXX_COMPILER_FLAG("-Wsuggest-override" SUGGEST_OVERRIDE)
if (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")
list(APPEND STRICT_OPTIONS_C "-fno-inline-small-functions")
@ -305,7 +328,6 @@ if(STRICT_OPTIONS_C)
list(REMOVE_DUPLICATES STRICT_OPTIONS_C)
endif()
set(GETTEXT_PACKAGE "linphone")
if(ENABLE_RELATIVE_PREFIX)
set(LINPHONE_DATA_DIR ".")
@ -318,6 +340,7 @@ if(WIN32)
endif()
set(PACKAGE_LOCALE_DIR "${LINPHONE_DATA_DIR}/${CMAKE_INSTALL_DATADIR}/locale")
set(PACKAGE_DATA_DIR "${LINPHONE_DATA_DIR}/${CMAKE_INSTALL_DATADIR}")
set(PACKAGE_GRAMMAR_DIR "${LINPHONE_DATA_DIR}/${CMAKE_INSTALL_DATADIR}/belr/grammars")
set(PACKAGE_SOUND_DIR "${LINPHONE_DATA_DIR}/${CMAKE_INSTALL_DATADIR}/sounds/linphone")
set(PACKAGE_RING_DIR "${PACKAGE_SOUND_DIR}/rings")
set(PACKAGE_FREEDESKTOP_DIR "${PACKAGE_DATA_DIR}/applications")
@ -339,8 +362,11 @@ endif()
add_subdirectory(include)
add_subdirectory(java)
add_subdirectory(src)
if(ENABLE_JAVA_WRAPPER)
add_subdirectory(wrappers/java)
endif()
add_subdirectory(coreapi)
add_subdirectory(src)
add_subdirectory(share)
if(ENABLE_CONSOLE_UI)
add_subdirectory(console)
@ -348,11 +374,6 @@ endif()
if(ENABLE_DAEMON)
add_subdirectory(daemon)
endif()
if(ENABLE_GTK_UI)
add_subdirectory(gtk)
add_subdirectory(pixmaps)
add_subdirectory(po)
endif()
if(ENABLE_TOOLS)
add_subdirectory(tools)
endif()

View file

@ -13,19 +13,22 @@ Building liblinphone
### Required dependencies
* *BcToolbox[2]*: portability layer
* *BelleSIP[3]*: SIP stack
* *Mediastreamer2[4]*: multimedia engine
* *Belcard[5]*: VCard support
* libxml2
* zlib
* libsqlite3: user data storage (disablable)
* gettext and libintl: internationalization support (disablable)
* **BcToolbox[2]:** portability layer
* **BelleSIP[3]:** SIP stack
* **Mediastreamer2[4]:** multimedia engine
* **Belcard[5]:** VCard support
* **libxml2**
* **zlib**
* **libsqlite3:** user data storage (disablable)
* **gettext** and **libintl**: internationalization support (disablable)
* **python interpreter** and **pystache**, **six** python module (needed for C++ wrapper and API documentaiton)
* **doxygen** and **dot** (needed for C++ wrapper and API documentation)
### Opitonal dependencies
* *Bzrtp[6]*: zrtp stack used for Linphone Instant Messaging Encryption
* **Bzrtp[6]**: zrtp stack used for Linphone Instant Messaging Encryption.
* For API documentatino generation: **sphinx**, **javasphinx**, **sphinx_csharp** python modules are needed.
### Build instructions
@ -38,18 +41,17 @@ Building liblinphone
### Supported build opitons
* `CMAKE_INSTALL_PREFIX=<string>` : install prefix
* `CMAKE_PREFIX_PATH=<string>` : column-separated list of prefixes where to search for dependencies
* `ENABLE_SHARED=NO` : do not build the shared library
* `ENABLE_STATIC=NO` : do not build the static library
* `ENABLE_STRICT=NO` : build without strict compilation flags (-Wall -Werror)
* `ENABLE_DOC=NO` : do not generate the reference documentation of liblinphone
* `ENABLE_UNIT_TESTS=NO` : do not build testing binaries
* `ENABLE_VCARD=NO` : disable VCard support
* `ENABLE_SQLITE_STORAGE=NO` : disable SQlite user data storage (message, history, contacts list)
* `ENABLE_TOOLS=NO` : do not build tool binaries
* `ENABLE_NLS=NO` : disable internationalization
* `ENABLE_LIME=YES` : disable Linphone Instant Messaging Encryption
* **`CMAKE_INSTALL_PREFIX=<string>`** : install prefix
* **`CMAKE_PREFIX_PATH=<string>`** : column-separated list of prefixes where to search for dependencies
* **`ENABLE_SHARED=NO`** : do not build the shared library
* **`ENABLE_STATIC=NO`** : do not build the static library
* **`ENABLE_STRICT=NO`** : build without strict compilation flags (-Wall -Werror)
* **`ENABLE_DOC=YES`** : Make the reference documentation of liblinphone to generated
* **`ENABLE_UNIT_TESTS=NO`** : do not build testing binaries
* **`ENABLE_VCARD=NO`** : disable VCard support
* **`ENABLE_SQLITE_STORAGE=NO`** : disable SQlite user data storage (message, history, contacts list)
* **`ENABLE_TOOLS=NO`** : do not build tool binaries
* **`ENABLE_LIME=YES`** : disable Linphone Instant Messaging Encryption
### Note for packagers
@ -92,4 +94,4 @@ Here is a short description of the content of the source tree.
- [3] belle-sip: git://git.linphone.org/belle-sip.git *or* <https://www.linphone.org/releases/sources/belle-sip>
- [4] mediastreamer2: git://git.linphone.org/mediastreamer2.git *or* <https://www.linphone.org/releases/sources/mediastreamer>
- [5] belcard: git://git.linphone.org/belcard.git *or* <https://www.linphone.org/releases/sources/belcard>
- [5] bzrtp: git://git.linphone.org/bzrtp.git *or* <https://www.linphone.org/releases/sources/bzrtp>
- [6] bzrtp: git://git.linphone.org/bzrtp.git *or* <https://www.linphone.org/releases/sources/bzrtp>

View file

@ -30,9 +30,13 @@ Requires: %{pkg_prefix}bctoolbox
Requires: %{pkg_prefix}ortp
Requires: %{pkg_prefix}mediastreamer
Requires: %{pkg_prefix}belle-sip
Requires: %{pkg_prefix}belr
%if @ENABLE_VCARD@
Requires: %{pkg_prefix}belcard
%endif
%if @ENABLE_SOCI_STORAGE@
Requires: %{pkg_prefix}soci
%endif
%description
liblinphone is the voip sdk used by Linphone
@ -116,6 +120,7 @@ rm -rf $RPM_BUILD_ROOT
%endif
%{_datadir}/Linphone/cmake/*.cmake
%{_datadir}/LinphoneCxx/cmake/*.cmake
%{_datadir}/belr/grammars/cpim_grammar
%changelog

View file

@ -1,54 +0,0 @@
############################################################################
# FindGtkMacIntegration.txt
# Copyright (C) 2015 Belledonne Communications, Grenoble France
#
############################################################################
#
# 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.
#
############################################################################
#
# - Find the libgtkmacintegration include file and library
#
# GTKMACINTEGRATION_FOUND - system has libgtkmacintegration
# GTKMACINTEGRATION_INCLUDE_DIRS - the libgtkmacintegration include directory
# GTKMACINTEGRATION_LIBRARIES - The libraries needed to use libgtkmacintegration
# GTKMACINTEGRATION_CPPFLAGS - The cflags needed to use libgtkmacintegration
set(_GTKMACINTEGRATION_ROOT_PATHS
${CMAKE_INSTALL_PREFIX}
)
find_path(GTKMACINTEGRATION_INCLUDE_DIRS
NAMES gtkosxapplication.h
HINTS _GTKMACINTEGRATION_ROOT_PATHS
PATH_SUFFIXES include/gtkmacintegration-gtk2 include/gtkmacintegration
)
find_library(GTKMACINTEGRATION_LIBRARIES
NAMES gtkmacintegration-gtk2 gtkmacintegration
HINTS ${_GTKMACINTEGRATION_ROOT_PATHS}
PATH_SUFFIXES bin lib
)
set(GTKMACINTEGRATION_CPPFLAGS "-DMAC_INTEGRATION")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GTKMACINTEGRATION
DEFAULT_MSG
GTKMACINTEGRATION_INCLUDE_DIRS GTKMACINTEGRATION_LIBRARIES GTKMACINTEGRATION_CPPFLAGS
)
mark_as_advanced(GTKMACINTEGRATION_INCLUDE_DIRS GTKMACINTEGRATION_LIBRARIES GTKMACINTEGRATION_CPPFLAGS)

View file

@ -1,6 +1,6 @@
############################################################################
# FindIntl.cmake
# Copyright (C) 2014 Belledonne Communications, Grenoble France
# FindLibXsd.cmake
# Copyright (C) 2017 Belledonne Communications, Grenoble France
#
############################################################################
#
@ -20,37 +20,29 @@
#
############################################################################
#
# - Find the libintl include file and library
# - Find the libxsd library
#
# INTL_FOUND - system has libintl
# INTL_INCLUDE_DIRS - the libintl include directory
# INTL_LIBRARIES - The libraries needed to use libintl
# LIBXSD_FOUND - system has libxsd
# LIBXSD_INCLUDE_DIRS - the libxsd include directory
# LIBXSD_LIBRARIES - The libraries needed to use libxsd
set(_INTL_ROOT_PATHS
${CMAKE_INSTALL_PREFIX}
)
find_path(INTL_INCLUDE_DIRS
NAMES libintl.h
HINTS _INTL_ROOT_PATHS
find_package(XercesC)
find_path(LIBXSD_INCLUDE_DIRS
NAMES xsd/cxx/config.hxx
PATH_SUFFIXES include
)
if(INTL_INCLUDE_DIRS)
set(HAVE_LIBINTL_H 1)
endif()
set(INTL_ARGS INTL_INCLUDE_DIRS HAVE_LIBINTL_H)
if(NOT UNIX OR APPLE)
find_library(INTL_LIBRARIES
NAMES intl
HINTS ${_INTL_ROOT_PATHS}
PATH_SUFFIXES bin lib
)
list(APPEND INTL_ARGS INTL_LIBRARIES)
if(LIBXSD_INCLUDE_DIRS)
list(APPEND LIBXSD_INCLUDE_DIRS ${XercesC_INCLUDE_DIRS})
endif()
set(LIBXSD_LIBRARIES ${XercesC_LIBRARIES})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Intl DEFAULT_MSG ${INTL_ARGS})
find_package_handle_standard_args(LibXsd
DEFAULT_MSG
LIBXSD_INCLUDE_DIRS LIBXSD_LIBRARIES
)
mark_as_advanced(${INTL_ARGS})
mark_as_advanced(LIBXSD_INCLUDE_DIRS LIBXSD_LIBRARIES)

View file

@ -25,6 +25,7 @@
#
SET(_SOCI_ALL_PLUGINS mysql sqlite3)
SET(_SOCI_REQUIRED_VARS SOCI_INCLUDE_DIRS SOCI_LIBRARIES)
SET(_SOCI_VERSION "_4_0")
#
### FIRST STEP: Find the soci headers.
@ -37,7 +38,7 @@ MARK_AS_ADVANCED(SOCI_INCLUDE_DIRS)
### SECOND STEP: Find the soci core library. Respect LIB_SUFFIX
#
FIND_LIBRARY(SOCI_LIBRARIES
NAMES soci_core
NAMES soci_core soci_core${_SOCI_VERSION}
PATH_SUFFIXES lib lib64)
MARK_AS_ADVANCED(SOCI_LIBRARIES)
@ -54,13 +55,17 @@ IF(SOCI_INCLUDE_DIRS AND SOCI_LIBRARIES)
FIND_LIBRARY(
SOCI_${plugin}_PLUGIN
NAMES soci_${plugin}
NAMES soci_${plugin} soci_${plugin}${_SOCI_VERSION}
PATH_SUFFIXES lib lib64)
MARK_AS_ADVANCED(SOCI_${plugin}_PLUGIN)
IF(SOCI_${plugin}_PLUGIN)
MESSAGE(STATUS " * Plugin ${plugin} found ${SOCI_${plugin}_PLUGIN}.")
SET(SOCI_${plugin}_FOUND True)
if(IOS OR ANDROID)
list(APPEND SOCI_LIBRARIES ${SOCI_${plugin}_PLUGIN})
endif()
ELSE()
MESSAGE(STATUS " * Plugin ${plugin} not found.")
SET(SOCI_${plugin}_FOUND False)
@ -84,4 +89,3 @@ ENDIF()
#
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Soci DEFAULT_MSG ${_SOCI_REQUIRED_VARS})

View file

@ -1,6 +1,6 @@
############################################################################
# CMakeLists.txt
# Copyright (C) 2014 Belledonne Communications, Grenoble France
# LinphoneUtils.cmake
# Copyright (C) 2018 Belledonne Communications, Grenoble France
#
############################################################################
#
@ -20,13 +20,14 @@
#
############################################################################
if(GETTEXT_FOUND)
foreach(language ${LINPHONE_ALL_LANGS_LIST})
GETTEXT_PROCESS_PO_FILES(${language} ALL PO_FILES ${language}.po)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${language}.gmo
DESTINATION ${PACKAGE_LOCALE_DIR}/${language}/LC_MESSAGES
RENAME linphone.mo
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)
endforeach()
endif()
function(check_python_module module_name)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import ${module_name}"
RESULT_VARIABLE result
OUTPUT_QUIET
ERROR_QUIET)
if(result EQUAL 0)
message(STATUS "'${module_name}' python module found")
else()
message(FATAL_ERROR "'${module_name}' python module not found")
endif()
endfunction()

View file

@ -35,16 +35,15 @@
#define PACKAGE_LOCALE_DIR "${PACKAGE_LOCALE_DIR}"
#define PACKAGE_DATA_DIR "${PACKAGE_DATA_DIR}"
#define PACKAGE_GRAMMAR_DIR "${PACKAGE_GRAMMAR_DIR}"
#define PACKAGE_SOUND_DIR "${PACKAGE_SOUND_DIR}"
#define PACKAGE_RING_DIR "${PACKAGE_RING_DIR}"
#cmakedefine BUILD_WIZARD
#cmakedefine HAVE_GTK_OSX 1
#cmakedefine HAVE_NOTIFY4
#cmakedefine HAVE_ZLIB 1
#cmakedefine HAVE_CU_GET_SUITE 1
#cmakedefine HAVE_CU_CURSES 1
#cmakedefine HAVE_LIBUDEV_H 0
#cmakedefine HAVE_LIME
#cmakedefine ENABLE_NLS 1
#cmakedefine ENABLE_UPDATE_CHECK 1

View file

@ -37,7 +37,7 @@ if(MSVC)
endif()
add_executable(linphonec ${LINPHONEC_SOURCE_FILES})
target_link_libraries(linphonec ${LINPHONE_LIBS_FOR_TOOLS} ${BCTOOLBOX_CORE_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES})
target_link_libraries(linphonec ${LINPHONE_LIBS_FOR_TOOLS} ${BCTOOLBOX_CORE_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${XSD_LIBRARIES})
set_target_properties(linphonec PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}")
if(INTL_FOUND)
@ -46,7 +46,7 @@ endif()
if(WIN32)
add_executable(linphoned WIN32 ${LINPHONEC_SOURCE_FILES})
target_link_libraries(linphoned ${LINPHONE_LIBS_FOR_TOOLS} ${BCTOOLBOX_CORE_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES})
target_link_libraries(linphoned ${LINPHONE_LIBS_FOR_TOOLS} ${BCTOOLBOX_CORE_LIBRARIES} ${ORTP_LIBRARIES} ${MEDIASTREAMER2_LIBRARIES} ${XSD_LIBRARIES})
if(INTL_FOUND)
target_link_libraries(linphoned ${INTL_LIBRARIES})
endif()

View file

@ -456,14 +456,15 @@ linphonec_parse_command_line(LinphoneCore *lc, char *cl)
char *
linphonec_command_generator(const char *text, int state)
{
static int index, len, adv;
static size_t len;
static int index, adv;
char *name;
if ( ! state )
{
index=0;
adv=0;
len=(int)strlen(text);
len=strlen(text);
}
/*
* Return the next name which partially matches
@ -665,8 +666,8 @@ lpc_cmd_transfer(LinphoneCore *lc, char *args)
const char *refer_to=NULL;
char arg1[256]={0};
char arg2[266]={0};
long id2=0;
int n=sscanf(args,"%255s %265s %li",arg1,arg2,&id2);
int id2=0;
int n=sscanf(args,"%255s %265s %d",arg1,arg2,&id2);
if (n==1 || isalpha(*arg1)){
call=linphone_core_get_current_call(lc);
if (call==NULL && bctbx_list_size(linphone_core_get_calls(lc))==1){
@ -679,13 +680,13 @@ lpc_cmd_transfer(LinphoneCore *lc, char *args)
}
linphone_call_transfer(call, refer_to);
}else if (n==2){
long id=atoi(arg1);
int id=atoi(arg1);
refer_to=args+strlen(arg1)+1;
call=linphonec_get_call(id);
if (call==NULL) return 0;
linphone_call_transfer(call, refer_to);
}else if (n==3){
long id=atoi(arg1);
int id=atoi(arg1);
call=linphonec_get_call(id);
call2=linphonec_get_call(id2);
if (call==NULL || call2==NULL) return 0;
@ -723,7 +724,7 @@ lpc_cmd_terminate(LinphoneCore *lc, char *args)
return 1;
}else{
/*the argument is a linphonec call id */
long id=atoi(args);
int id=atoi(args);
LinphoneCall *call=linphonec_get_call(id);
if (call){
if (linphone_call_terminate(call)==-1){
@ -764,9 +765,9 @@ lpc_cmd_redirect(LinphoneCore *lc, char *args){
}
} else {
char space;
long id;
int id;
int charRead;
if ( sscanf(args, "%li%c%n", &id, &space, &charRead) == 2 && space == ' ') {
if ( sscanf(args, "%d%c%n", &id, &space, &charRead) == 2 && space == ' ') {
LinphoneCall * call = linphonec_get_call(id);
if ( call != NULL ) {
if (linphone_call_get_state(call)!=LinphoneCallIncomingReceived) {
@ -799,8 +800,8 @@ lpc_cmd_answer(LinphoneCore *lc, char *args){
}
return 1;
}else{
long id;
if (sscanf(args,"%li",&id)==1){
int id;
if (sscanf(args,"%d",&id)==1){
LinphoneCall *call=linphonec_get_call (id);
if (linphone_call_accept(call)==-1){
linphonec_out("Fail to accept call %i\n",id);
@ -929,6 +930,7 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args)
return 1;
}
linphone_core_set_firewall_policy(lc,LinphonePolicyUseNatAddress);
setting = linphone_core_get_nat_address(lc);
}
}
@ -1003,14 +1005,14 @@ lpc_cmd_friend(LinphoneCore *lc, char *args)
{
args+=4;
if ( ! *args ) return 0;
friend_num = strtol(args, NULL, 10);
friend_num = (int)strtol(args, NULL, 10);
#ifndef _WIN32_WCE
if ( errno == ERANGE ) {
linphonec_out("Invalid friend number\n");
return 0;
}
#endif /*_WIN32_WCE*/
linphonec_friend_call(lc, friend_num);
linphonec_friend_call(lc, (unsigned int)friend_num);
return 1;
}
else if ( !strncmp(args, "delete", 6) )
@ -1025,7 +1027,7 @@ lpc_cmd_friend(LinphoneCore *lc, char *args)
}
else
{
friend_num = strtol(args, NULL, 10);
friend_num = (int)strtol(args, NULL, 10);
#ifndef _WIN32_WCE
if ( errno == ERANGE ) {
linphonec_out("Invalid friend number\n");
@ -1470,10 +1472,10 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){
}
if (args)
{
long id;
int n = sscanf(args, "%li", &id);
int id;
int n = sscanf(args, "%d", &id);
if (n == 1){
LinphoneCall *call=linphonec_get_call (id);
LinphoneCall *call=linphonec_get_call(id);
if (call){
if(linphone_call_resume(call)==-1){
linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args);
@ -1505,11 +1507,11 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){
}
static int lpc_cmd_conference(LinphoneCore *lc, char *args){
long id;
int id;
char subcommand[32]={0};
int n;
if (args==NULL) return 0;
n=sscanf(args, "%31s %li", subcommand,&id);
n=sscanf(args, "%31s %d", subcommand,&id);
if (n == 2){
LinphoneCall *call=linphonec_get_call(id);
if (call==NULL) return 1;
@ -2411,12 +2413,12 @@ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args)
#ifdef VIDEO_ENABLED
static int _lpc_cmd_video_window(LinphoneCore *lc, char *args, bool_t is_preview){
char subcommand[64];
long a,b;
int a,b;
int err;
VideoParams *params=is_preview ? &lpc_preview_params : &lpc_video_params;
if (!args) return 0;
err=sscanf(args,"%63s %ld %ld",subcommand,&a,&b);
err=sscanf(args,"%63s %d %d",subcommand,&a,&b);
if (err>=1){
if (strcmp(subcommand,"pos")==0){
if (err<3) return 0;
@ -2442,11 +2444,11 @@ static int _lpc_cmd_video_window(LinphoneCore *lc, char *args, bool_t is_preview
linphone_core_get_native_video_window_id (lc));
return 1;
} else if (err != 2) return 0;
params->wid=(void *)a;
params->wid=(void *)(long)a;
if (is_preview)
linphone_core_set_native_preview_window_id(lc, (void *)a);
linphone_core_set_native_preview_window_id(lc, (void *)(long)a);
else
linphone_core_set_native_video_window_id(lc, (void *)a);
linphone_core_set_native_video_window_id(lc, (void *)(long)a);
}else if (is_preview==TRUE){
if (strcmp(subcommand,"integrated")==0){
linphone_core_use_preview_window (lc,FALSE);
@ -2491,7 +2493,7 @@ static void lpc_display_call_states(LinphoneCore *lc){
tmp=linphone_call_get_remote_address_as_string (call);
flag=in_conference ? "conferencing" : "";
flag=linphone_call_has_transfer_pending(call) ? "transfer pending" : flag;
linphonec_out("%-2i | %-35s | %-15s | %s\n",VOIDPTR_TO_INT(linphone_call_get_user_pointer(call)),
linphonec_out("%-2i | %-35s | %-15s | %s\n",VOIDPTR_TO_INT(linphone_call_get_user_data(call)),
tmp,linphone_call_state_to_string(linphone_call_get_state(call))+strlen("LinphoneCall"),flag);
ms_free(tmp);
}

View file

@ -28,7 +28,6 @@
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
#include "private.h" /*coreapi/private.h, needed for LINPHONE_VERSION */
#endif /*_WIN32_WCE*/
#include <limits.h>
#include <ctype.h>
@ -111,9 +110,6 @@ static char **linephonec_readline_completion(const char *text,
/* These are callback for linphone core */
static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username, const char *domain);
static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to);
static void linphonec_display_something (LinphoneCore * lc, const char *something);
static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
static void linphonec_display_warning (LinphoneCore * lc, const char *something);
static void linphonec_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState new_call_state);
static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid);
@ -122,7 +118,6 @@ static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
const LinphoneAddress *from, const char *msg);
static void linphonec_display_status (LinphoneCore * lc, const char *something);
static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf);
static void print_prompt(LinphoneCore *opm);
void linphonec_out(const char *fmt,...);
@ -175,7 +170,7 @@ bool_t linphonec_camera_enabled=TRUE;
void linphonec_call_identify(LinphoneCall* call){
static int callid=1;
linphone_call_set_user_pointer (call,INT_TO_VOIDPTR(callid));
linphone_call_set_user_data (call,INT_TO_VOIDPTR(callid));
callid++;
}
@ -183,7 +178,7 @@ LinphoneCall *linphonec_get_call(int id){
const MSList *elem=linphone_core_get_calls(linphonec);
for (;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
if (VOIDPTR_TO_INT(linphone_call_get_user_pointer(call))==id){
if (VOIDPTR_TO_INT(linphone_call_get_user_data(call))==id){
return call;
}
}
@ -206,45 +201,6 @@ linphonec_display_refer (LinphoneCore * lc, const char *refer_to)
linphonec_out("Receiving out of call refer to %s\n", refer_to);
}
/*
* Linphone core callback
*/
static void
linphonec_display_something (LinphoneCore * lc, const char *something)
{
fprintf (stdout, "%s\n%s", something,prompt);
fflush(stdout);
}
/*
* Linphone core callback
*/
static void
linphonec_display_status (LinphoneCore * lc, const char *something)
{
fprintf (stdout, "%s\n%s", something,prompt);
fflush(stdout);
}
/*
* Linphone core callback
*/
static void
linphonec_display_warning (LinphoneCore * lc, const char *something)
{
fprintf (stdout, "Warning: %s\n%s", something,prompt);
fflush(stdout);
}
/*
* Linphone core callback
*/
static void
linphonec_display_url (LinphoneCore * lc, const char *something, const char *url)
{
fprintf (stdout, "%s : %s\n", something, url);
}
/*
* Linphone core callback
*/
@ -279,7 +235,7 @@ linphonec_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneC
char *remote=linphone_call_get_remote_address_as_string(call);
if (new_call_state==LinphoneCallConnected){
linphonec_out("The distant endpoint %s of call %i has been transfered, you can safely close the call.\n",
remote,VOIDPTR_TO_INT(linphone_call_get_user_pointer(call)));
remote,VOIDPTR_TO_INT(linphone_call_get_user_data(call)));
}
ms_free(remote);
}
@ -322,7 +278,7 @@ static void linphonec_call_updated(LinphoneCall *call){
}
static void linphonec_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t encrypted, const char *auth_token) {
int id=VOIDPTR_TO_INT(linphone_call_get_user_pointer(call));
int id=VOIDPTR_TO_INT(linphone_call_get_user_data(call));
if (!encrypted) {
linphonec_out("Call %i is not fully encrypted and auth token is %s.\n", id,
(auth_token != NULL) ? auth_token : "absent");
@ -334,7 +290,7 @@ static void linphonec_call_encryption_changed(LinphoneCore *lc, LinphoneCall *ca
static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){
char *from=linphone_call_get_remote_address_as_string(call);
int id=VOIDPTR_TO_INT(linphone_call_get_user_pointer(call));
int id=VOIDPTR_TO_INT(linphone_call_get_user_data(call));
switch(st){
case LinphoneCallEnd:
linphonec_out("Call %i with %s ended (%s).\n", id, from, linphone_reason_to_string(linphone_call_get_reason(call)));
@ -357,7 +313,7 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L
case LinphoneCallIncomingReceived:
linphonec_call_identify(call);
linphone_call_enable_camera (call,linphonec_camera_enabled);
id=VOIDPTR_TO_INT(linphone_call_get_user_pointer(call));
id=VOIDPTR_TO_INT(linphone_call_get_user_data(call));
linphonec_set_caller(from);
linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id);
if ( auto_answer) {
@ -373,7 +329,7 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L
break;
case LinphoneCallOutgoingInit:
linphonec_call_identify(call);
id=VOIDPTR_TO_INT(linphone_call_get_user_pointer(call));
id=VOIDPTR_TO_INT(linphone_call_get_user_data(call));
linphonec_out("Establishing call id to %s, assigned id %i\n", from,id);
break;
case LinphoneCallUpdatedByRemote:
@ -637,10 +593,6 @@ main (int argc, char *argv[]) {
linphonec_vtable.notify_presence_received = linphonec_notify_presence_received;
linphonec_vtable.new_subscription_requested = linphonec_new_unknown_subscriber;
linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
linphonec_vtable.display_status = linphonec_display_status;
linphonec_vtable.display_message=linphonec_display_something;
linphonec_vtable.display_warning=linphonec_display_warning;
linphonec_vtable.display_url=linphonec_display_url;
linphonec_vtable.text_received=linphonec_text_received;
linphonec_vtable.dtmf_received=linphonec_dtmf_received;
linphonec_vtable.refer_received=linphonec_display_refer;
@ -837,7 +789,7 @@ linphonec_prompt_for_auth_final(LinphoneCore *lc)
pending_auth=auth_stack.elem[auth_stack.nitems-1];
snprintf(auth_prompt, 256, "Password for %s on %s: ",
pending_auth->username, pending_auth->realm);
linphone_auth_info_get_username(pending_auth), linphone_auth_info_get_realm(pending_auth));
printf("\n");
#ifdef HAVE_READLINE

View file

@ -20,25 +20,12 @@
#
############################################################################
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
conference_private.h
contact_providers_priv.h
core_private.h
enum.h
lime.h
lpc2xml.h
@ -48,35 +35,22 @@ list(APPEND LINPHONE_PRIVATE_HEADER_FILES
sqlite3_bctbx_vfs.h
vcard_private.h
xml2lpc.h
platform-helpers.h
)
set(LINPHONE_SOURCE_FILES_C
account_creator.c
account_creator_service.c
address.c
authentication.c
bellesip_sal/sal_address_impl.c
bellesip_sal/sal_impl.c
bellesip_sal/sal_op_call.c
bellesip_sal/sal_op_call_transfer.c
bellesip_sal/sal_op_events.c
bellesip_sal/sal_op_impl.c
bellesip_sal/sal_op_info.c
bellesip_sal/sal_op_message.c
bellesip_sal/sal_op_presence.c
bellesip_sal/sal_op_publish.c
bellesip_sal/sal_op_registration.c
bellesip_sal/sal_sdp.c
buffer.c
callbacks.c
call_log.c
call_params.c
carddav.c
chat.c
chat_file_transfer.c
contactprovider.c
content.c
dial_plan.c
dict.c
ec-calibrator.c
@ -100,7 +74,6 @@ set(LINPHONE_SOURCE_FILES_C
lpc2xml.c
lpconfig.c
lsd.c
message_storage.c
misc.c
nat_policy.c
offeranswer.c
@ -111,7 +84,6 @@ set(LINPHONE_SOURCE_FILES_C
quality_reporting.c
remote_provisioning.c
ringtoneplayer.c
sal.c
siplogin.c
sipsetup.c
sqlite3_bctbx_vfs.c
@ -123,13 +95,16 @@ set(LINPHONE_SOURCE_FILES_C
)
set(LINPHONE_SOURCE_FILES_CXX
conference.cc
platform-helpers.cpp
android-helpers.cpp
ios-helpers.cpp
tester_utils.cpp
)
if(ANDROID)
list(APPEND LINPHONE_SOURCE_FILES_CXX linphonecore_jni.cc)
set_source_files_properties(linphonecore_jni.cc PROPERTIES COMPILE_DEFINITIONS "USE_JAVAH")
if(ENABLE_JAVA_WRAPPER)
list(APPEND LINPHONE_SOURCE_FILES_CXX ${LINPHONE_JNI_SOURCES})
set_source_files_properties(${LINPHONE_JNI_SOURCES} PROPERTIES GENERATED TRUE)
else()
if(ANDROID)
list(APPEND LINPHONE_SOURCE_FILES_C linphonecore_jni.cc)
endif()
endif()
set(LINPHONE_SOURCE_FILES_OBJC)
@ -149,54 +124,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}
)
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")
@ -208,103 +136,43 @@ else()
list(APPEND LINPHONE_SOURCE_FILES_C vcard_stubs.c)
endif()
bc_git_version(liblinphone ${PROJECT_VERSION})
add_definitions(
-DUSE_BELLESIP
-DBCTBX_LOG_DOMAIN="liblinphone"
-DLINPHONE_EXPORTS
)
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(ANDROID)
add_dependencies(linphone-static linphonecore-jni-header)
endif()
if(IOS)
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 ${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}"
)
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(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})
add_dependencies(linphone linphonecore-jni-header)
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()
target_include_directories(linphone-coreapi-static SYSTEM PRIVATE ${LINPHONE_INCLUDE_DIRS})
add_dependencies(linphone-coreapi-static liblinphone-git-version)
if (ENABLE_JAVA_WRAPPER)
add_dependencies(linphone-coreapi-static linphonej)
endif()
endif()
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)
if (ENABLE_JAVA_WRAPPER)
add_dependencies(linphone-coreapi linphonej)
endif()
endif ()
add_subdirectory(help)

View file

@ -39,7 +39,6 @@ liblinphone_la_SOURCES=\
chat_file_transfer.c \
conference.cc conference_private.h \
contactprovider.c contact_providers_priv.h \
content.c \
dial_plan.c \
dict.c \
ec-calibrator.c \

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) {
@ -45,7 +45,7 @@ void TunnelManager::addServer(const char *ip, int port) {
ms_warning("TunnelManager is configured in dual mode, use addServerPair instead");
return;
}
mServerAddrs.push_back(ServerAddr(ip,port));
if (mTunnelClient && !mUseDualClient) {
static_cast<TunnelClient*>(mTunnelClient)->addServer(ip,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) {
@ -70,7 +70,7 @@ void TunnelManager::addServerPair(const char *ip1, int port1, const char *ip2, i
ms_warning("TunnelManager is configured in single mode, use addServer instead");
return;
}
mDualServerAddrs.push_back(DualServerAddr(ip1, port1, ip2, port2));
if (mTunnelClient && mUseDualClient) {
static_cast<DualTunnelClient*>(mTunnelClient)->addServerPair(ip1, port1, ip2, port2);
@ -84,11 +84,8 @@ void TunnelManager::cleanServers() {
sal_end_background_task(mLongRunningTaskId);
mLongRunningTaskId = 0;
}
UdpMirrorClientList::iterator it;
for (it = mUdpMirrorClients.begin(); it != mUdpMirrorClients.end();) {
UdpMirrorClient& s=*it++;
s.stop();
}
for (auto &udpMirrorClient : mUdpMirrorClients)
udpMirrorClient.stop();
mUdpMirrorClients.clear();
mCurrentUdpMirrorClient = mUdpMirrorClients.end();
if (mTunnelClient) mTunnelClient->cleanServers();
@ -141,7 +138,7 @@ RtpTransport *TunnelManager::createRtpTransport(int port){
dualSocket->recvSocket = ((DualTunnelClient *)mTunnelClient)->createSocket(TunnelRecvOnly, port);
dualSocket->recvSocket->setUserPointer(this);
}
RtpTransport *t = ms_new0(RtpTransport,1);
t->t_getsocket=NULL;
t->t_recvfrom=customRecvfrom;
@ -161,15 +158,15 @@ void TunnelManager::startClient() {
} else {
mTunnelClient = TunnelClient::create(TRUE);
}
sal_set_tunnel(mCore->sal, mTunnelClient);
mCore->sal->setTunnel(mTunnelClient);
if (!mUseDualClient) {
static_cast<TunnelClient*>(mTunnelClient)->setCallback(tunnelCallback,this);
} else {
static_cast<DualTunnelClient*>(mTunnelClient)->setCallback(tunnelCallback2,this);
}
}
if (mVerifyServerCertificate) {
const char *rootCertificatePath = linphone_core_get_root_ca(mCore);
if (rootCertificatePath != NULL) {
@ -193,7 +190,7 @@ void TunnelManager::startClient() {
static_cast<TunnelClient*>(mTunnelClient)->addServer(addr.mAddr.c_str(), addr.mPort);
}
}
mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str());
if (!mTunnelClient->isStarted()) {
ms_message("Starting tunnel client");
@ -223,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;
}
@ -284,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);
}
@ -380,7 +377,7 @@ void TunnelManager::setMode(LinphoneTunnelMode mode) {
linphone_tunnel_mode_to_string(mode));
mMode = mode;
applyMode();
}
void TunnelManager::stopLongRunningTask() {
@ -393,7 +390,7 @@ void TunnelManager::stopLongRunningTask() {
void TunnelManager::tunnelCallback(bool connected, void *user_pointer){
TunnelManager *zis = static_cast<TunnelManager*>(user_pointer);
Event ev;
ev.mType=TunnelEvent;
ev.mData.mConnected=connected;
zis->postEvent(ev);
@ -402,7 +399,7 @@ void TunnelManager::tunnelCallback(bool connected, void *user_pointer){
void TunnelManager::tunnelCallback2(TunnelDirection direction, bool connected, void *user_pointer){
TunnelManager *zis = static_cast<TunnelManager*>(user_pointer);
Event ev;
ev.mType=TunnelEvent;
ev.mData.mConnected=connected;
zis->postEvent(ev);
@ -515,7 +512,7 @@ void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) {
void TunnelManager::networkReachableCb(LinphoneCore *lc, bool_t reachable) {
TunnelManager *tunnel = bcTunnel(linphone_core_get_tunnel(lc));
if (reachable) {
linphone_core_get_local_ip_for(AF_INET, NULL,tunnel->mLocalAddr);
if (tunnel->getMode() == LinphoneTunnelModeAuto){

View file

@ -1,6 +1,6 @@
/*
linphone
Copyright (C) 2010-2017 Belledonne Communications SARL
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
@ -20,11 +20,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "linphone/account_creator.h"
#include "linphone/core.h"
#include "linphone/lpconfig.h"
#include "private.h"
#include "c-wrapper/c-wrapper.h"
#include "dial-plan/dial-plan.h"
#include "bctoolbox/crypto.h"
#include "bctoolbox/regex.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
// =============================================================================
using namespace LinphonePrivate;
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneAccountCreatorCbs);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneAccountCreatorCbs, belle_sip_object_t,
@ -43,7 +54,7 @@ static const char* ha1_for_passwd(const char* username, const char* realm, const
static unsigned int validate_uri(const char* username, const char* domain, const char* display_name) {
LinphoneAddress* addr;
int status = 0;
unsigned int status = 0;
LinphoneProxyConfig* proxy = linphone_proxy_config_new();
linphone_proxy_config_set_identity(proxy, "sip:?@domain.com");
@ -79,7 +90,18 @@ static char* _get_identity(const LinphoneAccountCreator *creator) {
LinphoneAddress* addr;
addr = linphone_proxy_config_normalize_sip_uri(proxy, creator->username ? creator->username : creator->phone_number);
if (addr == NULL) goto end;
if (addr == NULL) {
if (creator->username && creator->domain) {
char *url = ms_strdup_printf("sip:%s@%s", creator->username, creator->domain);
addr = linphone_address_new(url);
ms_free(url);
if (addr == NULL) {
goto end;
}
} else {
goto end;
}
}
identity = linphone_address_as_string(addr);
linphone_address_unref(addr);
@ -103,11 +125,14 @@ LinphoneProxyConfig * linphone_account_creator_create_proxy_config(const Linphon
if (creator->phone_country_code) {
linphone_proxy_config_set_dial_prefix(cfg, creator->phone_country_code);
} else if (creator->phone_number) {
int dial_prefix_number = linphone_dial_plan_lookup_ccc_from_e164(creator->phone_number);
int dial_prefix_number = DialPlan::lookupCccFromE164(creator->phone_number);
char buff[4];
snprintf(buff, sizeof(buff), "%d", dial_prefix_number);
linphone_proxy_config_set_dial_prefix(cfg, buff);
}
if (linphone_proxy_config_get_server_addr(cfg) == NULL && creator->domain != NULL) {
linphone_proxy_config_set_server_addr(cfg, creator->domain);
}
linphone_proxy_config_enable_register(cfg, TRUE);
@ -332,7 +357,7 @@ void linphone_account_creator_set_user_data(LinphoneAccountCreator *creator, voi
LinphoneAccountCreatorUsernameStatus linphone_account_creator_set_username(LinphoneAccountCreator *creator, const char *username) {
int min_length = lp_config_get_int(creator->core->config, "assistant", "username_min_length", -1);
int max_length = lp_config_get_int(creator->core->config, "assistant", "username_max_length", -1);
bool_t use_phone_number = lp_config_get_int(creator->core->config, "assistant", "use_phone_number", 0);
bool_t use_phone_number = !!lp_config_get_int(creator->core->config, "assistant", "use_phone_number", 0);
const char* regex = lp_config_get_string(creator->core->config, "assistant", "username_regex", 0);
if (!username) {
creator->username = NULL;
@ -379,15 +404,15 @@ LinphoneAccountCreatorPhoneNumberStatusMask linphone_account_creator_set_phone_n
// if phone is valid, we lastly want to check that length is OK
{
const LinphoneDialPlan* plan = linphone_dial_plan_by_ccc(creator->phone_country_code);
const DialPlan &plan = DialPlan::findByCcc(creator->phone_country_code);
int size = (int)strlen(phone_number);
if (linphone_dial_plan_is_generic(plan)) {
if (plan.isGeneric()) {
return_status = LinphoneAccountCreatorPhoneNumberStatusInvalidCountryCode;
}
if (size < plan->nnl - 1) {
if (size < plan.getNationalNumberLength() - 1) {
return_status += LinphoneAccountCreatorPhoneNumberStatusTooShort;
goto end;
} else if (size > plan->nnl + 1) {
} else if (size > plan.getNationalNumberLength() + 1) {
return_status += LinphoneAccountCreatorPhoneNumberStatusTooLong;
goto end;
} else if (return_status & LinphoneAccountCreatorPhoneNumberStatusInvalidCountryCode) {
@ -1107,9 +1132,9 @@ LinphoneAccountCreatorStatus linphone_account_creator_update_password_linphone(L
return LinphoneAccountCreatorStatusMissingArguments;
}
const char * username = creator->username ? creator->username : creator->phone_number;
const char * ha1 = ms_strdup(creator->ha1 ? creator->ha1 : ha1_for_passwd(username, linphone_proxy_config_get_domain(creator->proxy_cfg), creator->password) );
const char * new_ha1 = ms_strdup(ha1_for_passwd(username, linphone_proxy_config_get_domain(creator->proxy_cfg), new_pwd));
const char *username = creator->username ? creator->username : creator->phone_number;
char *ha1 = bctbx_strdup(creator->ha1 ? creator->ha1 : ha1_for_passwd(username, linphone_proxy_config_get_domain(creator->proxy_cfg), creator->password) );
char *new_ha1 = bctbx_strdup(ha1_for_passwd(username, linphone_proxy_config_get_domain(creator->proxy_cfg), new_pwd));
ms_debug("Account creator: update_password (username=%s, domain=%s)",
creator->username,
@ -1125,6 +1150,9 @@ LinphoneAccountCreatorStatus linphone_account_creator_update_password_linphone(L
linphone_xml_rpc_session_send_request(creator->xmlrpc_session, request);
linphone_xml_rpc_request_unref(request);
bctbx_free(ha1);
bctbx_free(new_ha1);
return LinphoneAccountCreatorStatusRequestOk;
}
/****************** END OF UPDATE ACCOUNT **************************/

View file

@ -0,0 +1,201 @@
/*
account_creator.h
Copyright (C) 2017 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 _ACCOUNT_CREATOR_PRIVATE_H_
#define _ACCOUNT_CREATOR_PRIVATE_H_
#include "linphone/defs.h"
#include <belle-sip/object.h>
#include "linphone/account_creator_service.h"
#include "linphone/account_creator.h"
struct _LinphoneAccountCreatorService {
belle_sip_object_t base;
void *user_data;
LinphoneAccountCreatorRequestFunc account_creator_service_constructor_cb; /**< Constructor */
LinphoneAccountCreatorRequestFunc account_creator_service_destructor_cb; /**< Destructor */
LinphoneAccountCreatorRequestFunc create_account_request_cb; /**< Request to create account */
LinphoneAccountCreatorRequestFunc is_account_exist_request_cb; /**< Request to know if account exist */
LinphoneAccountCreatorRequestFunc activate_account_request_cb; /**< Request to activate account */
LinphoneAccountCreatorRequestFunc is_account_activated_request_cb; /**< Request to know if account is activated */
LinphoneAccountCreatorRequestFunc link_account_request_cb; /**< Request to link account with an alias */
LinphoneAccountCreatorRequestFunc activate_alias_request_cb; /**< Request to activate the link of alias */
LinphoneAccountCreatorRequestFunc is_alias_used_request_cb; /**< Request to know if alias is used */
LinphoneAccountCreatorRequestFunc is_account_linked_request_cb; /**< Request to know if account is linked with an alias */
LinphoneAccountCreatorRequestFunc recover_account_request_cb; /**< Request to recover account */
LinphoneAccountCreatorRequestFunc update_account_request_cb; /**< Request to update account */
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneAccountCreatorService);
struct _LinphoneAccountCreatorCbs {
belle_sip_object_t base;
void *user_data;
LinphoneAccountCreatorCbsStatusCb create_account_response_cb; /**< Response of create_account request */
LinphoneAccountCreatorCbsStatusCb is_account_exist_response_cb; /**< Response of is_account_exist request */
LinphoneAccountCreatorCbsStatusCb activate_account_response_cb; /**< Response of activate_account request */
LinphoneAccountCreatorCbsStatusCb is_account_activated_response_cb; /**< Response of is_account_activated request */
LinphoneAccountCreatorCbsStatusCb link_account_response_cb; /**< Response of link_account request */
LinphoneAccountCreatorCbsStatusCb activate_alias_response_cb; /**< Response of activation alias */
LinphoneAccountCreatorCbsStatusCb is_alias_used_response_cb; /**< Response of is_alias_used request */
LinphoneAccountCreatorCbsStatusCb is_account_linked_response_cb; /**< Response of is_account_linked request */
LinphoneAccountCreatorCbsStatusCb recover_account_response_cb; /**< Response of recover_account request */
LinphoneAccountCreatorCbsStatusCb update_account_response_cb; /**< Response of update_account request */
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneAccountCreatorCbs);
struct _LinphoneAccountCreator {
belle_sip_object_t base;
void *user_data;
LinphoneCore *core;
/* AccountCreator */
LinphoneAccountCreatorService *service; /**< Account creator service */
LinphoneAccountCreatorCbs *cbs; /**< Account creator cbs */
LinphoneXmlRpcSession *xmlrpc_session; /**< XML-RPC session */
LinphoneProxyConfig *proxy_cfg; /**< Default proxy config */
/* User */
char *username; /**< Username */
char *display_name; /**< Display name */
/* Password */
char *password; /**< Plain text password */
char *ha1; /**< Hash password */
/* Phone Number(Alias) */
char *phone_number; /**< User phone number*/
char *phone_country_code; /**< User phone number country code */
/* Email(Alias) */
char *email; /**< User email */
/* Misc */
char *language; /**< User language */
char *activation_code; /**< Account validation code */
char *domain; /**< Domain */
LinphoneTransportType transport; /**< Transport used */
/* Deprecated */
char *route;
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneAccountCreator);
#ifdef __cplusplus
extern "C" {
#endif
/**
* Account creator custom to set Linphone default values
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_constructor_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to test the existence of a Linphone account.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account_exist_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to create a Linphone account.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_create_account_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to activate a Linphone account with phone number.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_activate_account_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to activate a Linphone account with email.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_activate_email_account_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to test the validation of a Linphone account.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account_activated_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to test the existence a phone number with a Linphone account.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_phone_number_used_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to link a phone number with a Linphone account.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_link_phone_number_with_account_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to activate the link of a phone number with a Linphone account.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_activate_phone_number_link_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to a Linphone account with the phone number.
* @param[in] creator LinphoneAccountCreator object
* @return LinphoneAccountCreatorStatusRequestOk if the request has been sent, LinphoneAccountCreatorStatusRequestFailed otherwise
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_recover_phone_account_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to ask if an account is linked with a phone number
* @param[in] creator LinphoneAccountCreator object
* @return if this account is linked with a phone number
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_is_account_linked_linphone(LinphoneAccountCreator *creator);
/**
* Send an XML-RPC request to ask if an account is linked with a phone number
* @param[in] creator LinphoneAccountCreator object
* @param[in] new_pwd const char * : new password for the account creator
* @return LinphoneAccountCreatorStatusRequestOk if everything is OK, or a specific error otherwise.
**/
LINPHONE_PUBLIC LinphoneAccountCreatorStatus linphone_account_creator_update_password_linphone(LinphoneAccountCreator *creator);
#ifdef __cplusplus
}
#endif
#endif // _ACCOUNT_CREATOR_PRIVATE_H_

View file

@ -19,6 +19,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "linphone/account_creator_service.h"
#include "linphone/core.h"
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneAccountCreatorService);

View file

@ -1,221 +0,0 @@
/*
linphone
Copyright (C) 2009 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/core.h"
#include "linphone/lpconfig.h"
#include "private.h"
LinphoneAddress * _linphone_address_new(const char *addr){
SalAddress *saddr=sal_address_new(addr);
if (saddr==NULL)
ms_error("Cannot create LinphoneAddress, bad uri [%s]",addr);
return saddr;
}
LinphoneAddress * linphone_address_new(const char *addr) {
return _linphone_address_new(addr);
}
LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr){
return sal_address_clone(addr);
}
LinphoneAddress * linphone_address_ref(LinphoneAddress *addr){
return sal_address_ref(addr);
}
void linphone_address_unref(LinphoneAddress *addr){
sal_address_unref(addr);
}
const char *linphone_address_get_scheme(const LinphoneAddress *u){
return sal_address_get_scheme(u);
}
const char *linphone_address_get_display_name(const LinphoneAddress* u){
return sal_address_get_display_name(u);
}
const char *linphone_address_get_username(const LinphoneAddress *u){
return sal_address_get_username(u);
}
const char *linphone_address_get_domain(const LinphoneAddress *u){
return sal_address_get_domain(u);
}
int linphone_address_get_port(const LinphoneAddress *u) {
return sal_address_get_port(u);
}
LinphoneStatus linphone_address_set_display_name(LinphoneAddress *u, const char *display_name){
sal_address_set_display_name(u,display_name);
return 0;
}
LinphoneStatus linphone_address_set_username(LinphoneAddress *uri, const char *username) {
sal_address_set_username(uri,username);
return 0;
}
LinphoneStatus linphone_address_set_domain(LinphoneAddress *uri, const char *host){
sal_address_set_domain(uri,host);
return 0;
}
LinphoneStatus linphone_address_set_port(LinphoneAddress *uri, int port){
sal_address_set_port(uri,port);
return 0;
}
LinphoneStatus linphone_address_set_transport(LinphoneAddress *uri, LinphoneTransportType tp){
sal_address_set_transport(uri,(SalTransport)tp);
return 0;
}
LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri){
return (LinphoneTransportType)sal_address_get_transport(uri);
}
void linphone_address_set_method_param(LinphoneAddress *addr, const char *method) {
sal_address_set_method_param(addr, method);
}
const char *linphone_address_get_method_param(const LinphoneAddress *addr) {
return sal_address_get_method_param(addr);
}
void linphone_address_clean(LinphoneAddress *uri){
sal_address_clean(uri);
}
char *linphone_address_as_string(const LinphoneAddress *u){
return sal_address_as_string(u);
}
char *linphone_address_as_string_uri_only(const LinphoneAddress *u){
return sal_address_as_string_uri_only(u);
}
bool_t linphone_address_is_secure(const LinphoneAddress *uri){
return sal_address_is_secure(uri);
}
bool_t linphone_address_get_secure(const LinphoneAddress *uri){
return sal_address_is_secure(uri);
}
void linphone_address_set_secure(LinphoneAddress *addr, bool_t enabled){
sal_address_set_secure(addr, enabled);
}
bool_t linphone_address_is_sip(const LinphoneAddress *uri){
return sal_address_is_sip(uri);
}
static bool_t strings_equals(const char *s1, const char *s2){
if (s1==NULL && s2==NULL) return TRUE;
if (s1!=NULL && s2!=NULL && strcmp(s1,s2)==0) return TRUE;
return FALSE;
}
bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddress *a2){
const char *u1,*u2;
const char *h1,*h2;
int p1,p2;
u1=linphone_address_get_username(a1);
u2=linphone_address_get_username(a2);
p1=linphone_address_get_port(a1);
p2=linphone_address_get_port(a2);
h1=linphone_address_get_domain(a1);
h2=linphone_address_get_domain(a2);
return strings_equals(u1,u2) && strings_equals(h1,h2) && p1==p2;
}
bool_t linphone_address_equal(const LinphoneAddress *a1, const LinphoneAddress *a2) {
char *s1;
char *s2;
bool_t res;
if ((a1 == NULL) && (a2 == NULL)) return TRUE;
if ((a1 == NULL) || (a2 == NULL)) return FALSE;
s1 = linphone_address_as_string(a1);
s2 = linphone_address_as_string(a2);
res = (strcmp(s1, s2) == 0) ? TRUE : FALSE;
ms_free(s1);
ms_free(s2);
return res;
}
void linphone_address_destroy(LinphoneAddress *u){
linphone_address_unref(u);
}
void linphone_address_set_password(LinphoneAddress *addr, const char *passwd){
sal_address_set_password(addr,passwd);
}
const char *linphone_address_get_password(const LinphoneAddress *addr){
return sal_address_get_password(addr);
}
void linphone_address_set_header(LinphoneAddress *addr, const char *header_name, const char *header_value){
sal_address_set_header(addr,header_name,header_value);
}
const char *linphone_address_get_header(const LinphoneAddress *addr, const char *name){
return sal_address_get_header(addr,name);
}
bool_t linphone_address_has_param(const LinphoneAddress *addr, const char *name) {
return sal_address_has_param(addr, name);
}
const char * linphone_address_get_param(const LinphoneAddress *addr, const char *name) {
return sal_address_get_param(addr, name);
}
void linphone_address_set_param(LinphoneAddress *addr, const char *name, const char *value) {
sal_address_set_param(addr, name, value);
}
void linphone_address_set_params(LinphoneAddress *addr, const char *params) {
sal_address_set_params(addr, params);
}
void linphone_address_set_uri_param(LinphoneAddress *addr, const char *name, const char *value) {
sal_address_set_uri_param(addr, name, value);
}
void linphone_address_set_uri_params(LinphoneAddress *addr, const char *params) {
sal_address_set_uri_params(addr, params);
}
bool_t linphone_address_has_uri_param(const LinphoneAddress *addr, const char *name) {
return sal_address_has_uri_param(addr, name);
}
const char * linphone_address_get_uri_param(const LinphoneAddress *addr, const char *name) {
return sal_address_get_uri_param(addr, name);
}
LinphoneAddress * linphone_core_create_address(LinphoneCore *lc, const char *address) {
return linphone_address_new(address);
}
/** @} */

View file

@ -1,181 +0,0 @@
/*
linphone
Copyright (C) 2017 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.
*/
#ifdef __ANDROID__
#include "private.h"
#include "platform-helpers.h"
#include <jni.h>
namespace LinphonePrivate{
class AndroidPlatformHelpers : public PlatformHelpers{
public:
AndroidPlatformHelpers(LinphoneCore *lc, void *system_context);
virtual void setDnsServers();
virtual void acquireWifiLock();
virtual void releaseWifiLock();
virtual void acquireMcastLock();
virtual void releaseMcastLock();
virtual void acquireCpuLock();
virtual void releaseCpuLock();
~AndroidPlatformHelpers();
private:
int callVoidMethod(jmethodID id);
static jmethodID getMethodId(JNIEnv *env, jclass klass, const char *method, const char *signature);
jobject mJavaHelper;
jmethodID mWifiLockAcquireId;
jmethodID mWifiLockReleaseId;
jmethodID mMcastLockAcquireId;
jmethodID mMcastLockReleaseId;
jmethodID mCpuLockAcquireId;
jmethodID mCpuLockReleaseId;
jmethodID mGetDnsServersId;
jmethodID mGetPowerManagerId;
};
jmethodID AndroidPlatformHelpers::getMethodId(JNIEnv *env, jclass klass, const char *method, const char *signature){
jmethodID id = env->GetMethodID(klass, method, signature);
if (id == 0){
ms_fatal("Could not find java method '%s %s'", method, signature);
}
return id;
}
AndroidPlatformHelpers::AndroidPlatformHelpers(LinphoneCore *lc, void *system_context) : PlatformHelpers(lc) {
JNIEnv *env=ms_get_jni_env();
jclass klass = env->FindClass("org/linphone/core/util/AndroidPlatformHelper");
if (!klass){
ms_fatal("Could not find java AndroidPlatformHelper class");
return;
}
jmethodID ctor = env->GetMethodID(klass,"<init>", "(Ljava/lang/Object;)V");
mJavaHelper = env->NewObject(klass, ctor, (jobject)system_context);
if (!mJavaHelper){
ms_error("Could not instanciate AndroidPlatformHelper object.");
return;
}
mJavaHelper = (jobject) env->NewGlobalRef(mJavaHelper);
mWifiLockAcquireId = getMethodId(env, klass, "acquireWifiLock", "()V");
mWifiLockReleaseId = getMethodId(env, klass, "releaseWifiLock", "()V");
mMcastLockAcquireId = getMethodId(env, klass, "acquireMcastLock", "()V");
mMcastLockReleaseId = getMethodId(env, klass, "releaseMcastLock", "()V");
mCpuLockAcquireId = getMethodId(env, klass, "acquireCpuLock", "()V");
mCpuLockReleaseId = getMethodId(env, klass, "releaseCpuLock", "()V");
mGetDnsServersId = getMethodId(env, klass, "getDnsServers", "()[Ljava/lang/String;");
mGetPowerManagerId = getMethodId(env, klass, "getPowerManager", "()Ljava/lang/Object;");
jobject pm = env->CallObjectMethod(mJavaHelper,mGetPowerManagerId);
belle_sip_wake_lock_init(env, pm);
ms_message("AndroidPlatformHelpers is fully initialised");
}
AndroidPlatformHelpers::~AndroidPlatformHelpers(){
if (mJavaHelper){
JNIEnv *env = ms_get_jni_env();
belle_sip_wake_lock_uninit(env);
env->DeleteGlobalRef(mJavaHelper);
mJavaHelper = NULL;
}
}
void AndroidPlatformHelpers::setDnsServers(){
if (!mJavaHelper || linphone_core_get_dns_set_by_app(mCore)) return;
JNIEnv *env=ms_get_jni_env();
if (env && mJavaHelper) {
jobjectArray jservers = (jobjectArray)env->CallObjectMethod(mJavaHelper,mGetDnsServersId);
bctbx_list_t *l = NULL;
if (env->ExceptionCheck()) {
env->ExceptionClear();
ms_error("AndroidPlatformHelpers::setDnsServers() exception");
return;
}
if (jservers != NULL){
int count = env->GetArrayLength(jservers);
for (int i=0; i < count; i++) {
jstring jserver = (jstring) env->GetObjectArrayElement(jservers, i);
const char *str = env->GetStringUTFChars(jserver, NULL);
if (str){
l = bctbx_list_append(l, ms_strdup(str));
env->ReleaseStringUTFChars(jserver, str);
}
}
}
linphone_core_set_dns_servers(mCore, l);
bctbx_list_free_with_data(l, ms_free);
}
}
void AndroidPlatformHelpers::acquireWifiLock(){
callVoidMethod(mWifiLockAcquireId);
}
void AndroidPlatformHelpers::releaseWifiLock(){
callVoidMethod(mWifiLockReleaseId);
}
void AndroidPlatformHelpers::acquireMcastLock(){
callVoidMethod(mMcastLockAcquireId);
}
void AndroidPlatformHelpers::releaseMcastLock(){
callVoidMethod(mMcastLockReleaseId);
}
void AndroidPlatformHelpers::acquireCpuLock(){
callVoidMethod(mCpuLockAcquireId);
}
void AndroidPlatformHelpers::releaseCpuLock(){
callVoidMethod(mCpuLockReleaseId);
}
int AndroidPlatformHelpers::callVoidMethod(jmethodID id) {
JNIEnv *env=ms_get_jni_env();
if (env && mJavaHelper) {
env->CallVoidMethod(mJavaHelper,id);
if (env->ExceptionCheck()) {
env->ExceptionClear();
return -1;
} else
return 0;
} else
return -1;
}
PlatformHelpers *createAndroidPlatformHelpers(LinphoneCore *lc, void *system_context){
return new AndroidPlatformHelpers(lc, system_context);
}
}//end of namespace
#endif

View file

@ -23,8 +23,13 @@
*/
#include "linphone/core.h"
#include "private.h"
#include "linphone/lpconfig.h"
#include "sal/sal.h"
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj);
static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthInfo *src);
@ -41,6 +46,10 @@ BELLE_SIP_INSTANCIATE_VPTR(
);
LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain){
return linphone_auth_info_new_for_algorithm(username, userid, passwd, ha1, realm, domain, NULL);
}
LinphoneAuthInfo *linphone_auth_info_new_for_algorithm(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain, const char *algorithm){
LinphoneAuthInfo *obj=belle_sip_object_new(LinphoneAuthInfo);
if (username!=NULL && (strlen(username)>0) ) obj->username=ms_strdup(username);
if (userid!=NULL && (strlen(userid)>0)) obj->userid=ms_strdup(userid);
@ -48,6 +57,17 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri
if (ha1!=NULL && (strlen(ha1)>0)) obj->ha1=ms_strdup(ha1);
if (realm!=NULL && (strlen(realm)>0)) obj->realm=ms_strdup(realm);
if (domain!=NULL && (strlen(domain)>0)) obj->domain=ms_strdup(domain);
if (!algorithm)
obj->algorithm = ms_strdup("MD5");
if(algorithm && strcasecmp(algorithm, "MD5") && strcasecmp(algorithm, "SHA-256")){
ms_error("Given algorithm %s is not correct.", algorithm);
return NULL;
}
if(algorithm)
obj->algorithm=ms_strdup(algorithm);
return obj;
}
@ -62,6 +82,7 @@ static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthIn
if (src->tls_key) dst->tls_key = ms_strdup(src->tls_key);
if (src->tls_cert_path) dst->tls_cert_path = ms_strdup(src->tls_cert_path);
if (src->tls_key_path) dst->tls_key_path = ms_strdup(src->tls_key_path);
if (src->algorithm) dst->algorithm = ms_strdup(src->algorithm);
}
LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){
@ -81,6 +102,10 @@ const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i) {
}
const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i) {
return linphone_auth_info_get_password(i);
}
const char *linphone_auth_info_get_password(const LinphoneAuthInfo *i) {
return i->passwd;
}
@ -116,8 +141,11 @@ const char *linphone_auth_info_get_tls_key_path(const LinphoneAuthInfo *i) {
return i->tls_key_path;
}
void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd) {
linphone_auth_info_set_password(info, passwd);
}
void linphone_auth_info_set_password(LinphoneAuthInfo *info, const char *passwd) {
if (info->passwd) {
ms_free(info->passwd);
info->passwd = NULL;
@ -208,6 +236,7 @@ static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj) {
if (obj->tls_key != NULL) ms_free(obj->tls_key);
if (obj->tls_cert_path != NULL) ms_free(obj->tls_cert_path);
if (obj->tls_key_path != NULL) ms_free(obj->tls_key_path);
if (obj->algorithm != NULL) ms_free(obj->algorithm);
}
/**
@ -219,7 +248,7 @@ void linphone_auth_info_destroy(LinphoneAuthInfo *obj){
void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, int pos) {
char key[50];
bool_t store_ha1_passwd = lp_config_get_int(config, "sip", "store_ha1_passwd", 1);
bool_t store_ha1_passwd = !!lp_config_get_int(config, "sip", "store_ha1_passwd", 1);
sprintf(key, "auth_info_%i", pos);
lp_config_clean_section(config, key);
@ -228,9 +257,16 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in
return;
}
if (!obj->ha1 && obj->realm && obj->passwd && (obj->username || obj->userid) && store_ha1_passwd) {
/*compute ha1 to avoid storing clear text password*/
obj->ha1 = reinterpret_cast<char *>(ms_malloc(33));
sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1);
/* Default algorithm is MD5 if it's NULL */
if((obj->algorithm==NULL)||(!(strcasecmp(obj->algorithm, "MD5")))){
obj->ha1 = reinterpret_cast<char *>(ms_malloc(33));
sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1);
}
/* If algorithm is SHA-256, calcul ha1 by sha256*/
if((obj->algorithm)&&(!(strcasecmp(obj->algorithm, "SHA-256")))){
obj->ha1 = reinterpret_cast<char *>(ms_malloc(65));
sal_auth_compute_ha1_for_algorithm(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1,65, obj->algorithm);
}
}
if (obj->username != NULL) {
lp_config_set_string(config, key, "username", obj->username);
@ -262,6 +298,9 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in
if (obj->tls_key_path != NULL) {
lp_config_set_string(config, key, "client_cert_key", obj->tls_key_path);
}
if (obj->algorithm != NULL) {
lp_config_set_string(config, key, "algorithm", obj->algorithm);
}
}
LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int pos)
@ -413,8 +452,6 @@ LinphoneAuthInfo * linphone_core_create_auth_info(LinphoneCore *lc, const char *
void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info){
LinphoneAuthInfo *ai;
bctbx_list_t *elem;
bctbx_list_t *l;
int restarted_op_count=0;
bool_t updating=FALSE;
@ -433,10 +470,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=sal_get_pending_auths(lc->sal);elem!=NULL;elem=elem->next){
SalOp *op=(SalOp*)elem->data;
auto pendingAuths = lc->sal->getPendingAuths();
for (const auto &op : pendingAuths) {
LinphoneAuthInfo *ai;
const SalAuthInfo *req_sai=sal_op_get_auth_requested(op);
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;
@ -446,6 +483,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
sai.realm=ai->realm;
sai.password=ai->passwd;
sai.ha1=ai->ha1;
sai.algorithm=ai->algorithm;
if (ai->tls_cert && ai->tls_key) {
sal_certificates_chain_parse(&sai, ai->tls_cert, SAL_CERTIFICATE_RAW_FORMAT_PEM);
sal_signing_key_parse(&sai, ai->tls_key, "");
@ -455,16 +493,16 @@ 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 == sal_op_get_user_pointer(op)) {
if (proxy->data == op->getUserPointer()) {
linphone_proxy_config_set_state((LinphoneProxyConfig*)(proxy->data),LinphoneRegistrationProgress,"Authentication...");
break;
}
}
sal_op_authenticate(op,&sai);
op->authenticate(&sai);
restarted_op_count++;
}
}
if (l){
if (!pendingAuths.empty()) {
ms_message("linphone_core_add_auth_info(): restarted [%i] operation(s) after %s auth info for\n"
"\tusername: [%s]\n"
"\trealm [%s]\n"
@ -475,7 +513,6 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
info->realm ? info->realm : "",
info->domain ? info->domain : "");
}
bctbx_list_free(l);
write_auth_infos(lc);
}

View file

@ -33,7 +33,7 @@ SalAddress * sal_address_new(const char *uri){
}
SalAddress * sal_address_clone(const SalAddress *addr){
return (SalAddress *) belle_sip_object_ref(belle_sip_object_clone(BELLE_SIP_OBJECT(addr)));
return (SalAddress *) belle_sip_object_ref(belle_sip_header_address_clone(BELLE_SIP_HEADER_ADDRESS(addr)));
}
const char *sal_address_get_scheme(const SalAddress *addr){
@ -58,7 +58,7 @@ void sal_address_set_secure(SalAddress *addr, bool_t enabled){
bool_t sal_address_is_secure(const SalAddress *addr){
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);
if (uri) return belle_sip_uri_is_secure(uri);
if (uri) return !!belle_sip_uri_is_secure(uri);
return FALSE;
}
@ -199,7 +199,7 @@ void sal_address_set_param(SalAddress *addr,const char* name,const char* value){
bool_t sal_address_has_param(const SalAddress *addr, const char *name){
belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(addr);
return belle_sip_parameters_has_parameter(parameters, name);
return !!belle_sip_parameters_has_parameter(parameters, name);
}
const char * sal_address_get_param(const SalAddress *addr, const char *name) {
@ -224,7 +224,7 @@ void sal_address_set_uri_params(SalAddress *addr, const char *params){
bool_t sal_address_has_uri_param(const SalAddress *addr, const char *name){
belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr)));
return belle_sip_parameters_has_parameter(parameters, name);
return !!belle_sip_parameters_has_parameter(parameters, name);
}
const char * sal_address_get_uri_param(const SalAddress *addr, const char *name) {
@ -282,4 +282,3 @@ bool_t sal_address_is_ipv6(const SalAddress *addr){
void sal_address_destroy(SalAddress *addr){
sal_address_unref(addr);
}

File diff suppressed because it is too large Load diff

View file

@ -20,167 +20,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef SAL_IMPL_H_
#define SAL_IMPL_H_
#include "sal/sal.h"
#include "c-wrapper/internal/c-sal.h"
#include "belle-sip/belle-sip.h"
#include "belle-sip/belle-sdp.h"
struct Sal{
MSFactory *factory;
SalCallbacks callbacks;
MSList *pending_auths;/*MSList of SalOp */
belle_sip_stack_t* stack;
belle_sip_provider_t *prov;
belle_sip_header_user_agent_t* user_agent;
belle_sip_listener_t *listener;
void *tunnel_client;
void *up; /*user pointer*/
int session_expires;
unsigned int keep_alive;
char *root_ca;
char *root_ca_data;
char *uuid;
int refresher_retry_after; /*retry after value for refresher*/
MSList *supported_tags;/*list of char * */
belle_sip_header_t *supported;
bool_t one_matching_codec;
bool_t use_tcp_tls_keep_alive;
bool_t nat_helper_enabled;
bool_t tls_verify;
bool_t tls_verify_cn;
bool_t use_dates;
bool_t auto_contacts;
bool_t enable_test_features;
bool_t no_initial_route;
bool_t enable_sip_update; /*true by default*/
SalOpSDPHandling default_sdp_handling;
bool_t pending_trans_checking; /*testing purpose*/
void *ssl_config;
bctbx_list_t *supported_content_types; /* list of char* */
belle_tls_crypto_config_postcheck_callback_t tls_postcheck_cb;
void *tls_postcheck_cb_data;
};
typedef enum SalOpState {
SalOpStateEarly=0
,SalOpStateActive
,SalOpStateTerminating /*this state is used to wait until a proceeding state, so we can send the cancel*/
,SalOpStateTerminated
}SalOpState;
const char* sal_op_state_to_string(SalOpState value);
typedef enum SalOpDir {
SalOpDirIncoming=0
,SalOpDirOutgoing
}SalOpDir;
typedef enum SalOpType {
SalOpUnknown,
SalOpRegister,
SalOpCall,
SalOpMessage,
SalOpPresence,
SalOpPublish,
SalOpSubscribe
}SalOpType;
const char* sal_op_type_to_string(SalOpType type);
struct SalOp{
SalOpBase base;
const belle_sip_listener_callbacks_t *callbacks;
SalErrorInfo error_info;
SalErrorInfo reason_error_info;
belle_sip_client_transaction_t *pending_auth_transaction;
belle_sip_server_transaction_t* pending_server_trans;
belle_sip_server_transaction_t* pending_update_server_trans;
belle_sip_client_transaction_t* pending_client_trans;
SalAuthInfo* auth_info;
belle_sip_dialog_t* dialog;
belle_sip_header_replaces_t *replaces;
belle_sip_header_referred_by_t *referred_by;
SalMediaDescription *result;
belle_sdp_session_description_t *sdp_answer;
SalOpState state;
SalOpDir dir;
belle_sip_refresher_t* refresher;
int ref;
SalOpType type;
SalPrivacyMask privacy;
belle_sip_header_event_t *event; /*used by SalOpSubscribe kinds*/
SalOpSDPHandling sdp_handling;
int auth_requests; /*number of auth requested for this op*/
bool_t cnx_ip_to_0000_if_sendonly_enabled;
bool_t auto_answer_asked;
bool_t sdp_offering;
bool_t call_released;
bool_t manual_refresher;
bool_t has_auth_pending;
bool_t supports_session_timers;
bool_t op_released;
};
belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal);
belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *desc);
int sdp_to_media_description(belle_sdp_session_description_t *sdp, SalMediaDescription *desc);
belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method);
void sal_op_call_fill_cbs(SalOp*op);
void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog);
/*return reffed op*/
SalOp* sal_op_ref(SalOp* op);
/*return null, destroy op if ref count =0*/
void* sal_op_unref(SalOp* op);
void sal_op_release_impl(SalOp *op);
void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces);
void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message);
int sal_op_send_request(SalOp* op, belle_sip_request_t* request);
int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires);
void sal_op_resend_request(SalOp* op, belle_sip_request_t* request);
int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener );
belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_request_t *req, int code);
/*
* return true if both from and to uri are sips
* */
bool_t sal_op_is_secure(const SalOp* op);
void sal_process_authentication(SalOp *op);
belle_sip_header_contact_t* sal_op_create_contact(SalOp *op) ;
bool_t _sal_compute_sal_errors(belle_sip_response_t* response, SalReason* sal_reason, char* reason, size_t reason_size);
SalReason _sal_reason_from_sip_code(int code);
void sal_op_set_reason_error_info(SalOp *op, belle_sip_message_t *msg);
void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response);
/*presence*/
void sal_op_presence_fill_cbs(SalOp*op);
/*messaging*/
void sal_op_message_fill_cbs(SalOp*op);
void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event);
void sal_op_subscribe_fill_cbs(SalOp*op);
/*call transfer*/
void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t *tr);
void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t *tr);
/*create SalAuthInfo by copying username and realm from suth event*/
SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) ;
void sal_add_pending_auth(Sal *sal, SalOp *op);
void sal_remove_pending_auth(Sal *sal, SalOp *op);
void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceModel *presence);
belle_sip_response_t *sal_create_response_from_request(Sal *sal, belle_sip_request_t *req, int code);
void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming);
SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg);
int sal_reason_to_sip_code(SalReason r);
void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg);
SalSubscribeStatus belle_sip_message_get_subscription_state(const belle_sip_message_t *msg);
#endif /* SAL_IMPL_H_ */

File diff suppressed because it is too large Load diff

View file

@ -1,273 +0,0 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications, Grenoble, France
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 "sal_impl.h"
#include "offeranswer.h"
/*call transfer*/
static void sal_op_set_referred_by(SalOp* op,belle_sip_header_referred_by_t* referred_by) {
if (op->referred_by){
belle_sip_object_unref(op->referred_by);
}
op->referred_by=referred_by;
belle_sip_object_ref(op->referred_by);
}
int sal_call_refer_to(SalOp *op, belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by){
char* tmp;
belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):sal_op_build_request(op, "REFER");
if (!req) {
tmp=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)));
ms_error("Cannot refer to [%s] for op [%p]",tmp,op);
belle_sip_free(tmp);
return -1;
}
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to));
if (referred_by) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(referred_by));
return sal_op_send_request(op,req);
}
int sal_call_refer(SalOp *op, const char *refer_to){
belle_sip_header_address_t *referred_by;
belle_sip_header_refer_to_t* refer_to_header;
if (op->dialog) {
referred_by=(belle_sip_header_address_t*)belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_dialog_get_local_party(op->dialog)));
}else{
referred_by=BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op));
}
refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to));
return sal_call_refer_to(op,refer_to_header,belle_sip_header_referred_by_create(referred_by));
}
int sal_call_refer_with_replaces(SalOp *op, SalOp *other_call_op){
belle_sip_dialog_state_t other_call_dialog_state=other_call_op->dialog?belle_sip_dialog_get_state(other_call_op->dialog):BELLE_SIP_DIALOG_NULL;
belle_sip_dialog_state_t op_dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL;
belle_sip_header_replaces_t* replaces;
belle_sip_header_refer_to_t* refer_to;
belle_sip_header_referred_by_t* referred_by;
const char* from_tag;
const char* to_tag;
char* escaped_replaces;
/*first, build refer to*/
if ((other_call_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) && (other_call_dialog_state!=BELLE_SIP_DIALOG_EARLY)) {
ms_error("wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED or BELE_SIP_DIALOG_EARLY",
belle_sip_dialog_state_to_string(other_call_dialog_state),
other_call_op);
return -1;
}
if (op_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) {
ms_error("wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED",
belle_sip_dialog_state_to_string(op_dialog_state),
op);
return -1;
}
refer_to=belle_sip_header_refer_to_create(belle_sip_dialog_get_remote_party(other_call_op->dialog));
belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(refer_to));
/*rfc3891
...
4. User Agent Client Behavior: Sending a Replaces Header
A User Agent that wishes to replace a single existing early or
confirmed dialog with a new dialog of its own, MAY send the target
User Agent an INVITE request containing a Replaces header field. The
User Agent Client (UAC) places the Call-ID, to-tag, and from-tag
information for the target dialog in a single Replaces header field
and sends the new INVITE to the target.*/
from_tag=belle_sip_dialog_get_local_tag(other_call_op->dialog);
to_tag=belle_sip_dialog_get_remote_tag(other_call_op->dialog);
replaces=belle_sip_header_replaces_create(belle_sip_header_call_id_get_call_id(belle_sip_dialog_get_call_id(other_call_op->dialog))
,from_tag,to_tag);
escaped_replaces=belle_sip_header_replaces_value_to_escaped_string(replaces);
belle_sip_uri_set_header(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)),"Replaces",escaped_replaces);
belle_sip_free(escaped_replaces);
referred_by=belle_sip_header_referred_by_create(belle_sip_dialog_get_local_party(op->dialog));
belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(referred_by));
return sal_call_refer_to(op,refer_to,referred_by);
}
/*
int sal_call_accept_refer(SalOp *h){
ms_fatal("sal_call_accept_refer not implemented yet");
return -1;
}*/
/*informs this call is consecutive to an incoming refer */
int sal_call_set_referer(SalOp *h, SalOp *refered_call){
if (refered_call->replaces)
sal_op_set_replaces(h,refered_call->replaces);
if (refered_call->referred_by)
sal_op_set_referred_by(h,refered_call->referred_by);
return 0;
}
/* returns the SalOp of a call that should be replaced by h, if any */
SalOp *sal_call_get_replaces(SalOp *op){
if (op && op->replaces){
/*rfc3891
3. User Agent Server Behavior: Receiving a Replaces Header
The Replaces header contains information used to match an existing
SIP dialog (call-id, to-tag, and from-tag). Upon receiving an INVITE
with a Replaces header, the User Agent (UA) attempts to match this
information with a confirmed or early dialog. The User Agent Server
(UAS) matches the to-tag and from-tag parameters as if they were tags
present in an incoming request. In other words, the to-tag parameter
is compared to the local tag, and the from-tag parameter is compared
to the remote tag.
*/
belle_sip_dialog_t* dialog=belle_sip_provider_find_dialog(op->base.root->prov
,belle_sip_header_replaces_get_call_id(op->replaces)
,belle_sip_header_replaces_get_to_tag(op->replaces)
,belle_sip_header_replaces_get_from_tag(op->replaces));
if (!dialog) {
/*for backward compatibility with liblinphone <= 3.10.2-243 */
dialog=belle_sip_provider_find_dialog(op->base.root->prov
,belle_sip_header_replaces_get_call_id(op->replaces)
,belle_sip_header_replaces_get_from_tag(op->replaces)
,belle_sip_header_replaces_get_to_tag(op->replaces));
}
if (dialog) {
return (SalOp*)belle_sip_dialog_get_application_data(dialog);
}
}
return NULL;
}
static int send_notify_for_refer(SalOp* op, int code, const char *reason){
belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY");
char *sipfrag=belle_sip_strdup_printf("SIP/2.0 %i %s\r\n",code,reason);
size_t content_length=strlen(sipfrag);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,-1)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),belle_sip_header_create("Event","refer"));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_type_create("message","sipfrag")));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length)));
belle_sip_message_assign_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length);
return sal_op_send_request(op,notify);
}
static void notify_last_response(SalOp *op, SalOp *newcall){
belle_sip_client_transaction_t *tr=newcall->pending_client_trans;
belle_sip_response_t *resp=NULL;
if (tr){
resp=belle_sip_transaction_get_response((belle_sip_transaction_t*)tr);
}
if (resp==NULL){
send_notify_for_refer(op, 100, "Trying");
}else{
send_notify_for_refer(op, belle_sip_response_get_status_code(resp), belle_sip_response_get_reason_phrase(resp));
}
}
int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){
belle_sip_dialog_state_t state;
if(belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_TERMINATED){
return 0;
}
state = newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL;
switch(state) {
case BELLE_SIP_DIALOG_EARLY:
send_notify_for_refer(op, 100, "Trying");
break;
case BELLE_SIP_DIALOG_CONFIRMED:
send_notify_for_refer(op, 200, "Ok");
break;
case BELLE_SIP_DIALOG_TERMINATED:
case BELLE_SIP_DIALOG_NULL:
notify_last_response(op,newcall);
break;
}
return 0;
}
void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t *server_transaction){
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
belle_sip_header_refer_to_t *refer_to= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_refer_to_t);
belle_sip_header_referred_by_t *referred_by= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_referred_by_t);
belle_sip_response_t* resp;
belle_sip_uri_t* refer_to_uri;
char* refer_to_uri_str;
ms_message("Receiving REFER request on op [%p]",op);
if (refer_to) {
refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to));
if (refer_to_uri && belle_sip_uri_get_header(refer_to_uri,"Replaces")) {
sal_op_set_replaces(op,belle_sip_header_replaces_create2(belle_sip_uri_get_header(refer_to_uri,"Replaces")));
belle_sip_uri_remove_header(refer_to_uri,"Replaces");
}
if (referred_by){
sal_op_set_referred_by(op,referred_by);
}
refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri);
resp = sal_op_create_response_from_request(op,req,202);
belle_sip_server_transaction_send_response(server_transaction,resp);
op->base.root->callbacks.refer_received(op->base.root,op,refer_to_uri_str);
belle_sip_free(refer_to_uri_str);
} else {
ms_warning("cannot do anything with the refer without destination\n");
resp = sal_op_create_response_from_request(op,req,400);
belle_sip_server_transaction_send_response(server_transaction,resp);
}
}
void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction){
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
belle_sip_header_t* header_event=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event");
belle_sip_header_content_type_t* content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t);
belle_sip_response_t* resp;
ms_message("Receiving NOTIFY request on op [%p]",op);
if (header_event
&& strncasecmp(belle_sip_header_get_unparsed_value(header_event),"refer",strlen("refer"))==0
&& content_type
&& strcmp(belle_sip_header_content_type_get_type(content_type),"message")==0
&& strcmp(belle_sip_header_content_type_get_subtype(content_type),"sipfrag")==0
&& body){
belle_sip_response_t* sipfrag=BELLE_SIP_RESPONSE(belle_sip_message_parse(body));
if (sipfrag){
int code=belle_sip_response_get_status_code(sipfrag);
SalReferStatus status=SalReferFailed;
if (code<200){
status=SalReferTrying;
}else if (code<300){
status=SalReferSuccess;
}else if (code>=400){
status=SalReferFailed;
}
belle_sip_object_unref(sipfrag);
resp = sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
op->base.root->callbacks.notify_refer(op,status);
}
}else{
ms_error("Notify without sipfrag or not for 'refer' event package, rejecting");
resp = sal_op_create_response_from_request(op,req,489);
belle_sip_server_transaction_send_response(server_transaction,resp);
}
}

View file

@ -1,385 +0,0 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications, Grenoble, France
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 "sal_impl.h"
SalSubscribeStatus belle_sip_message_get_subscription_state(const belle_sip_message_t *msg){
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(msg,belle_sip_header_subscription_state_t);
SalSubscribeStatus sss=SalSubscribeNone;
if (subscription_state_header){
if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED)==0)
sss=SalSubscribeTerminated;
else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_PENDING)==0)
sss=SalSubscribePending;
else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE)==0)
sss=SalSubscribeActive;
}
return sss;
}
static void subscribe_refresher_listener (belle_sip_refresher_t* refresher
,void* user_pointer
,unsigned int status_code
,const char* reason_phrase, int will_retry) {
SalOp* op = (SalOp*)user_pointer;
belle_sip_transaction_t *tr=BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher));
/*belle_sip_response_t* response=belle_sip_transaction_get_response(tr);*/
SalSubscribeStatus sss=SalSubscribeTerminated;
ms_message("Subscribe refresher [%i] reason [%s] ",status_code,reason_phrase?reason_phrase:"none");
if (status_code>=200 && status_code<300){
if (status_code==200) sss=SalSubscribeActive;
else if (status_code==202) sss=SalSubscribePending;
set_or_update_dialog(op,belle_sip_transaction_get_dialog(tr));
op->base.root->callbacks.subscribe_response(op,sss, will_retry);
} else if (status_code >= 300) {
SalReason reason = SalReasonUnknown;
if (status_code == 503) { /*refresher returns 503 for IO error*/
reason = SalReasonIOError;
}
sal_error_info_set(&op->error_info, reason, "SIP", status_code,reason_phrase,NULL);
op->base.root->callbacks.subscribe_response(op,sss, will_retry);
}else if (status_code==0){
op->base.root->callbacks.on_expire(op);
}
}
static void subscribe_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
SalOp *op = (SalOp*)user_ctx;
belle_sip_object_t *src = belle_sip_io_error_event_get_source(event);
if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(src, belle_sip_client_transaction_t)){
belle_sip_client_transaction_t *tr = BELLE_SIP_CLIENT_TRANSACTION(src);
belle_sip_request_t* req = belle_sip_transaction_get_request((belle_sip_transaction_t*)tr);
const char *method=belle_sip_request_get_method(req);
if (!op->dialog) {
/*this is handling outgoing out-of-dialog notifies*/
if (strcmp(method,"NOTIFY")==0){
SalErrorInfo *ei=&op->error_info;
sal_error_info_set(ei,SalReasonIOError, "SIP", 0,NULL,NULL);
op->base.root->callbacks.on_notify_response(op);
}
}
}
}
static void subscribe_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) {
belle_sip_dialog_t *dialog = belle_sip_dialog_terminated_event_get_dialog(event);
SalOp* op= (SalOp*)ctx;
if (op->dialog) {
if (belle_sip_dialog_terminated_event_is_expired(event)){
if (!belle_sip_dialog_is_server(dialog)){
/*notify the app that our subscription is dead*/
const char *eventname = NULL;
if (op->event){
eventname = belle_sip_header_event_get_package_name(op->event);
}
op->base.root->callbacks.notify(op, SalSubscribeTerminated, eventname, NULL);
}else{
op->base.root->callbacks.incoming_subscribe_closed(op);
}
}
set_or_update_dialog(op, NULL);
}
}
static void subscribe_response_event(void *op_base, const belle_sip_response_event_t *event){
SalOp *op = (SalOp*)op_base;
belle_sip_request_t * req;
const char *method;
belle_sip_client_transaction_t *tr = belle_sip_response_event_get_client_transaction(event);
if (!tr) return;
req = belle_sip_transaction_get_request((belle_sip_transaction_t*)tr);
method = belle_sip_request_get_method(req);
if (!op->dialog) {
if (strcmp(method,"NOTIFY")==0){
sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event));
op->base.root->callbacks.on_notify_response(op);
}
}
}
static void subscribe_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
SalOp *op = (SalOp*)user_ctx;
belle_sip_request_t * req;
const char *method;
belle_sip_client_transaction_t *tr = belle_sip_timeout_event_get_client_transaction(event);
if (!tr) return;
req = belle_sip_transaction_get_request((belle_sip_transaction_t*)tr);
method = belle_sip_request_get_method(req);
if (!op->dialog) {
/*this is handling outgoing out-of-dialog notifies*/
if (strcmp(method,"NOTIFY")==0){
SalErrorInfo *ei=&op->error_info;
sal_error_info_set(ei,SalReasonRequestTimeout, "SIP", 0,NULL,NULL);
op->base.root->callbacks.on_notify_response(op);
}
}
}
static void subscribe_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
}
static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *eventname, SalBodyHandler* body_handler){
SalSubscribeStatus sub_state;
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t);
belle_sip_response_t* resp;
belle_sip_server_transaction_t* server_transaction = op->pending_server_trans;
if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) {
sub_state=SalSubscribeTerminated;
ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op));
} else
sub_state=SalSubscribeActive;
sal_op_ref(op);
op->base.root->callbacks.notify(op,sub_state,eventname,body_handler);
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
sal_op_unref(op);
}
static void subscribe_process_request_event(void *op_base, const belle_sip_request_event_t *event) {
SalOp* op = (SalOp*)op_base;
belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
belle_sip_dialog_state_t dialog_state;
belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);
belle_sip_header_event_t *event_header;
belle_sip_body_handler_t *body_handler;
belle_sip_response_t* resp;
const char *eventname=NULL;
const char *method=belle_sip_request_get_method(req);
belle_sip_dialog_t *dialog = NULL;
belle_sip_object_ref(server_transaction);
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
op->pending_server_trans=server_transaction;
event_header=belle_sip_message_get_header_by_type(req,belle_sip_header_event_t);
body_handler = BELLE_SIP_BODY_HANDLER(sal_op_get_body_handler(op, BELLE_SIP_MESSAGE(req)));
if (event_header==NULL){
ms_warning("No event header in incoming SUBSCRIBE.");
resp=sal_op_create_response_from_request(op,req,400);
belle_sip_server_transaction_send_response(server_transaction,resp);
if (!op->dialog) sal_op_release(op);
return;
}
if (op->event==NULL) {
op->event=event_header;
belle_sip_object_ref(op->event);
}
eventname=belle_sip_header_event_get_package_name(event_header);
if (!op->dialog) {
if (strcmp(method,"SUBSCRIBE")==0){
dialog = belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction));
if (!dialog){
resp=sal_op_create_response_from_request(op,req,481);
belle_sip_server_transaction_send_response(server_transaction,resp);
sal_op_release(op);
return;
}
set_or_update_dialog(op, dialog);
ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
}else{ /*this is a NOTIFY*/
handle_notify(op, req, eventname, (SalBodyHandler *)body_handler);
return;
}
}
dialog_state=belle_sip_dialog_get_state(op->dialog);
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL: {
const char *type = NULL;
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_type_t);
if (content_type) type = belle_sip_header_content_type_get_type(content_type);
op->base.root->callbacks.subscribe_received(op, eventname, type ? (SalBodyHandler *)body_handler : NULL);
break;
}
case BELLE_SIP_DIALOG_EARLY:
ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",belle_sip_request_get_method(req),op->dialog);
break;
case BELLE_SIP_DIALOG_CONFIRMED:
if (strcmp("NOTIFY",method)==0) {
handle_notify(op, req, eventname, (SalBodyHandler *)body_handler);
} else if (strcmp("SUBSCRIBE",method)==0) {
/*either a refresh of an unsubscribe*/
if (expires && belle_sip_header_expires_get_expires(expires)>0) {
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
} else if(expires) {
ms_message("Unsubscribe received from [%s]",sal_op_get_from(op));
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
op->base.root->callbacks.incoming_subscribe_closed(op);
}
}
break;
default: {
ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
}
}
}
static belle_sip_listener_callbacks_t op_subscribe_callbacks={ 0 };
/*Invoke when sal_op_release is called by upper layer*/
static void sal_op_release_cb(struct SalOpBase* op_base) {
SalOp *op =(SalOp*)op_base;
if(op->refresher) {
belle_sip_refresher_stop(op->refresher);
belle_sip_object_unref(op->refresher);
op->refresher=NULL;
set_or_update_dialog(op,NULL); /*only if we have refresher. else dialog terminated event will remove association*/
}
}
void sal_op_subscribe_fill_cbs(SalOp*op) {
if (op_subscribe_callbacks.process_io_error==NULL){
op_subscribe_callbacks.process_io_error=subscribe_process_io_error;
op_subscribe_callbacks.process_response_event=subscribe_response_event;
op_subscribe_callbacks.process_timeout=subscribe_process_timeout;
op_subscribe_callbacks.process_transaction_terminated=subscribe_process_transaction_terminated;
op_subscribe_callbacks.process_request_event=subscribe_process_request_event;
op_subscribe_callbacks.process_dialog_terminated=subscribe_process_dialog_terminated;
}
op->callbacks=&op_subscribe_callbacks;
op->type=SalOpSubscribe;
op->base.release_cb=sal_op_release_cb;
}
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler){
belle_sip_request_t *req=NULL;
if (from)
sal_op_set_from(op,from);
if (to)
sal_op_set_to(op,to);
if (!op->dialog){
sal_op_subscribe_fill_cbs(op);
req=sal_op_build_request(op,"SUBSCRIBE");
if( req == NULL ) {
return -1;
}
sal_op_set_event(op, eventname);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->event));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler));
return sal_op_send_and_create_refresher(op,req,expires,subscribe_refresher_listener);
}else if (op->refresher){
const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
/* modify last request to update body*/
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_req), BELLE_SIP_BODY_HANDLER(body_handler));
return belle_sip_refresher_refresh(op->refresher,expires);
}
ms_warning("sal_subscribe(): no dialog and no refresher ?");
return -1;
}
int sal_unsubscribe(SalOp *op){
if (op->refresher){
const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_req), NULL, 0);
belle_sip_refresher_refresh(op->refresher,0);
return 0;
}
return -1;
}
int sal_subscribe_accept(SalOp *op){
belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans));
belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t);
belle_sip_response_t* resp = sal_op_create_response_from_request(op,req,200);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(expires));
belle_sip_server_transaction_send_response(op->pending_server_trans,resp);
return 0;
}
int sal_notify_pending_state(SalOp *op){
if (op->dialog != NULL && op->pending_server_trans) {
belle_sip_request_t* notify;
belle_sip_header_subscription_state_t* sub_state;
ms_message("Sending NOTIFY with subscription state pending for op [%p]",op);
if (!(notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"))) {
ms_error("Cannot create NOTIFY on op [%p]",op);
return -1;
}
if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(op->event));
sub_state=belle_sip_header_subscription_state_new();
belle_sip_header_subscription_state_set_state(sub_state,BELLE_SIP_SUBSCRIPTION_STATE_PENDING);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify), BELLE_SIP_HEADER(sub_state));
return sal_op_send_request(op,notify);
} else {
ms_warning("NOTIFY with subscription state pending for op [%p] not implemented in this case (either dialog pending trans does not exist",op);
}
return 0;
}
int sal_subscribe_decline(SalOp *op, SalReason reason){
belle_sip_response_t* resp = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),
sal_reason_to_sip_code(reason));
belle_sip_server_transaction_send_response(op->pending_server_trans,resp);
return 0;
}
int sal_notify(SalOp *op, const SalBodyHandler *body_handler){
belle_sip_request_t* notify;
if (op->dialog){
if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1;
}else{
sal_op_subscribe_fill_cbs(op);
notify = sal_op_build_request(op, "NOTIFY");
}
if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(op->event));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,op->dialog ?
BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)) :
BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,0))
);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(notify), BELLE_SIP_BODY_HANDLER(body_handler));
return sal_op_send_request(op,notify);
}
int sal_notify_close(SalOp *op){
belle_sip_request_t* notify;
if (!op->dialog) return -1;
if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1;
if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(op->event));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1)));
return sal_op_send_request(op,notify);
}

View file

@ -17,488 +17,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "sal_impl.h"
/*create an operation */
SalOp * sal_op_new(Sal *sal){
SalOp *op=ms_new0(SalOp,1);
__sal_op_init(op,sal);
op->type=SalOpUnknown;
op->privacy=SalPrivacyNone;
op->manual_refresher=FALSE;/*tells that requests with expiry (SUBSCRIBE, PUBLISH) will be automatically refreshed*/
op->sdp_handling=sal->default_sdp_handling;
sal_op_ref(op);
return op;
}
void sal_op_kill_dialog(SalOp *op) {
ms_warning("op [%p]: force kill of dialog [%p]", op, op->dialog);
belle_sip_dialog_delete(op->dialog);
}
void sal_op_release(SalOp *op){
/*if in terminating state, keep this state because it means we are waiting for a response to be able to terminate the operation.*/
if (op->state!=SalOpStateTerminating)
op->state=SalOpStateTerminated;
sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn't not mean freeing op. Make sure back pointer will not be used later*/
if (op->base.release_cb)
op->base.release_cb(&op->base);
if (op->refresher) {
belle_sip_refresher_stop(op->refresher);
}
op->op_released = TRUE;
sal_op_unref(op);
}
void sal_op_release_impl(SalOp *op){
ms_message("Destroying op [%p] of type [%s]",op,sal_op_type_to_string(op->type));
if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction);
sal_remove_pending_auth(op->base.root,op);
if (op->auth_info) {
sal_auth_info_delete(op->auth_info);
}
if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer);
if (op->refresher) {
belle_sip_object_unref(op->refresher);
op->refresher=NULL;
}
if (op->result)
sal_media_description_unref(op->result);
if(op->replaces) belle_sip_object_unref(op->replaces);
if(op->referred_by) belle_sip_object_unref(op->referred_by);
if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans);
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans);
if (op->event) belle_sip_object_unref(op->event);
sal_error_info_reset(&op->error_info);
__sal_op_free(op);
return ;
}
void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){
if (op->type == SalOpRegister) {
/*Registration authenticate is just about registering again*/
sal_register_refresh(op,-1);
}else {
/*for sure auth info will be accessible from the provider*/
sal_process_authentication(op);
}
return ;
}
void sal_op_cancel_authentication(SalOp *h){
ms_fatal("sal_op_cancel_authentication not implemented yet");
return ;
}
SalAuthInfo * sal_op_get_auth_requested(SalOp *op){
return op->auth_info;
}
belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){
belle_sip_header_contact_t* contact_header;
belle_sip_uri_t* contact_uri;
if (sal_op_get_contact_address(op)) {
contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op)));
} else {
contact_header= belle_sip_header_contact_new();
}
if (!(contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header)))) {
/*no uri, just creating a new one*/
contact_uri=belle_sip_uri_new();
belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact_header),contact_uri);
}
belle_sip_uri_set_user_password(contact_uri,NULL);
belle_sip_uri_set_secure(contact_uri,sal_op_is_secure(op));
if (op->privacy!=SalPrivacyNone){
belle_sip_uri_set_user(contact_uri,NULL);
}
/*don't touch contact in case of gruu*/
if (!belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header))),"gr")) {
belle_sip_header_contact_set_automatic(contact_header,op->base.root->auto_contacts);
if (op->base.root->uuid){
if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){
char *instance_id=belle_sip_strdup_printf("\"<urn:uuid:%s>\"",op->base.root->uuid);
belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance",instance_id);
belle_sip_free(instance_id);
}
}
}
return contact_header;
}
static void add_initial_route_set(belle_sip_request_t *request, const MSList *list){
const MSList *elem;
for (elem=list;elem!=NULL;elem=elem->next){
SalAddress *addr=(SalAddress*)elem->data;
belle_sip_header_route_t *route;
belle_sip_uri_t *uri;
/*Optimization: if the initial route set only contains one URI which is the same as the request URI, ommit it*/
if (elem==list && list->next==NULL){
belle_sip_uri_t *requri=belle_sip_request_get_uri(request);
/*skip the first route it is the same as the request uri*/
if (strcmp(sal_address_get_domain(addr),belle_sip_uri_get_host(requri))==0 ){
ms_message("Skipping top route of initial route-set because same as request-uri.");
continue;
}
}
route=belle_sip_header_route_create((belle_sip_header_address_t*)addr);
uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)route);
belle_sip_uri_set_lr_param(uri,1);
belle_sip_message_add_header((belle_sip_message_t*)request,(belle_sip_header_t*)route);
}
}
belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) {
belle_sip_header_from_t* from_header;
belle_sip_header_to_t* to_header;
belle_sip_provider_t* prov=op->base.root->prov;
belle_sip_request_t *req;
belle_sip_uri_t* req_uri;
belle_sip_uri_t* to_uri;
belle_sip_header_call_id_t *call_id_header;
const SalAddress* to_address;
const MSList *elem=sal_op_get_route_addresses(op);
char token[10];
/* check that the op has a correct to address */
to_address = sal_op_get_to_address(op);
if( to_address == NULL ){
ms_error("No To: address, cannot build request");
return NULL;
}
to_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_address));
if( to_uri == NULL ){
ms_error("To: address is invalid, cannot build request");
return NULL;
}
if (strcmp("REGISTER",method)==0 || op->privacy==SalPrivacyNone) {
from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op))
,belle_sip_random_token(token,sizeof(token)));
} else {
from_header=belle_sip_header_from_create2("Anonymous <sip:anonymous@anonymous.invalid>",belle_sip_random_token(token,sizeof(token)));
}
/*make sure to preserve components like headers or port*/
req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)to_uri);
belle_sip_uri_set_secure(req_uri,sal_op_is_secure(op));
to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(to_address),NULL);
belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to_header))), "gr"); /*remove gruu in any case*/
call_id_header = belle_sip_provider_create_call_id(prov);
if (sal_op_get_call_id(op)) {
belle_sip_header_call_id_set_call_id(call_id_header, sal_op_get_call_id(op));
}
req=belle_sip_request_create(
req_uri,
method,
call_id_header,
belle_sip_header_cseq_create(20,method),
from_header,
to_header,
belle_sip_header_via_new(),
70);
if (op->privacy & SalPrivacyId) {
belle_sip_header_p_preferred_identity_t* p_preferred_identity=belle_sip_header_p_preferred_identity_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(p_preferred_identity));
}
if (elem && strcmp(method,"REGISTER")!=0 && !op->base.root->no_initial_route){
add_initial_route_set(req,elem);
}
if (strcmp("REGISTER",method)!=0 && op->privacy!=SalPrivacyNone ){
belle_sip_header_privacy_t* privacy_header=belle_sip_header_privacy_new();
if (op->privacy&SalPrivacyCritical)
belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyCritical));
if (op->privacy&SalPrivacyHeader)
belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyHeader));
if (op->privacy&SalPrivacyId)
belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyId));
if (op->privacy&SalPrivacyNone)
belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyNone));
if (op->privacy&SalPrivacySession)
belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacySession));
if (op->privacy&SalPrivacyUser)
belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyUser));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(privacy_header));
}
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->base.root->supported);
return req;
}
belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_request_t *req, int code){
return sal_create_response_from_request(op->base.root,req,code);
}
/*ping: main purpose is to obtain its own contact address behind firewalls*/
int sal_ping(SalOp *op, const char *from, const char *to){
sal_op_set_from(op,from);
sal_op_set_to(op,to);
return sal_op_send_request(op,sal_op_build_request(op,"OPTIONS"));
}
void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces) {
if (op->replaces){
belle_sip_object_unref(op->replaces);
}
op->replaces=replaces;
belle_sip_object_ref(op->replaces);
}
void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) {
belle_sip_header_user_agent_t* user_agent=belle_sip_message_get_header_by_type(message,belle_sip_header_user_agent_t);
char user_agent_string[256];
if (user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) {
if (op->base.remote_ua!=NULL){
ms_free(op->base.remote_ua);
}
op->base.remote_ua=ms_strdup(user_agent_string);
}
}
int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires) {
belle_sip_header_expires_t* expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_EXPIRES);
if (!expires_header && expires>=0) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new()));
}
if (expires_header) belle_sip_header_expires_set_expires(expires_header,expires);
return sal_op_send_request(op,request);
}
void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) {
belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ);
belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
sal_op_send_request(op,request);
}
static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *msg){
if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){
belle_sip_header_contact_t* newct;
/*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/
sal_op_set_contact_address(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h));
newct = sal_op_create_contact(op);
belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct));
return;
}
/*if a header already exists in the message, replace it*/
belle_sip_message_set_header(msg,h);
}
void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){
if (op->base.sent_custom_headers){
belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers;
belle_sip_list_t *l=belle_sip_message_get_all_headers(ch);
belle_sip_list_t *elem;
for(elem=l;elem!=NULL;elem=elem->next){
add_headers(op,(belle_sip_header_t*)elem->data,msg);
}
belle_sip_list_free(l);
}
}
static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request, bool_t add_contact) {
belle_sip_client_transaction_t* client_transaction;
belle_sip_provider_t* prov=op->base.root->prov;
belle_sip_uri_t* outbound_proxy=NULL;
belle_sip_header_contact_t* contact;
int result =-1;
belle_sip_uri_t *next_hop_uri=NULL;
if (add_contact && !belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t)) {
contact = sal_op_create_contact(op);
belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact));
} /*keep existing*/
_sal_op_add_custom_headers(op, (belle_sip_message_t*)request);
if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) {
/*don't put route header if dialog is in confirmed state*/
const MSList *elem=sal_op_get_route_addresses(op);
const char *transport;
const char *method=belle_sip_request_get_method(request);
belle_sip_listening_point_t *udplp=belle_sip_provider_get_listening_point(prov,"UDP");
if (elem) {
outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data);
next_hop_uri=outbound_proxy;
}else{
next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request));
}
transport=belle_sip_uri_get_transport_param(next_hop_uri);
if (transport==NULL){
/*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use
* the first available transport*/
if (!belle_sip_uri_is_secure(next_hop_uri)){
if (udplp==NULL){
if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){
transport="tcp";
}else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){
transport="tls";
}
}
if (transport){
belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport);
belle_sip_uri_set_transport_param(next_hop_uri,transport);
}
}
}else{
#ifdef TUNNEL_ENABLED
if (udplp && BELLE_SIP_OBJECT_IS_INSTANCE_OF(udplp,belle_sip_tunnel_listening_point_t)){
/* our tunnel mode only supports UDP. Force transport to be set to UDP */
belle_sip_uri_set_transport_param(next_hop_uri,"udp");
}
#endif
}
/*because in case of tunnel, transport can be changed*/
transport=belle_sip_uri_get_transport_param(next_hop_uri);
if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport &&
(strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){
/*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/
belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t);
belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"alias",NULL);
}
}
client_transaction = belle_sip_provider_create_client_transaction(prov,request);
belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op));
if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans);
op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/
belle_sip_object_ref(op->pending_client_trans);
if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL)
belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent));
if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION)
&& !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) {
/*hmm just in case we already have authentication param in cache*/
belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL,op->base.realm);
}
result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/);
/*update call id if not set yet for this OP*/
if (result == 0 && !op->base.call_id) {
op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_call_id_t))));
}
return result;
}
int sal_op_send_request(SalOp* op, belle_sip_request_t* request) {
bool_t need_contact=FALSE;
if (request==NULL) {
return -1; /*sanity check*/
}
/*
Header field where proxy ACK BYE CAN INV OPT REG
___________________________________________________________
Contact R o - - m o o
*/
if (strcmp(belle_sip_request_get_method(request),"INVITE")==0
||strcmp(belle_sip_request_get_method(request),"REGISTER")==0
||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0
||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0
||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/
need_contact=TRUE;
return _sal_op_send_request_with_contact(op, request,need_contact);
}
int sal_reason_to_sip_code(SalReason r){
int ret=500;
switch(r){
case SalReasonNone:
ret=200;
break;
case SalReasonIOError:
ret=503;
break;
case SalReasonUnknown:
ret=400;
break;
case SalReasonBusy:
ret=486;
break;
case SalReasonDeclined:
ret=603;
break;
case SalReasonDoNotDisturb:
ret=600;
break;
case SalReasonForbidden:
ret=403;
break;
case SalReasonUnsupportedContent:
ret=415;
break;
case SalReasonNotFound:
ret=404;
break;
case SalReasonRedirect:
ret=302;
break;
case SalReasonTemporarilyUnavailable:
ret=480;
break;
case SalReasonServiceUnavailable:
ret=503;
break;
case SalReasonRequestPending:
ret=491;
break;
case SalReasonUnauthorized:
ret=401;
break;
case SalReasonNotAcceptable:
ret=488; /*or maybe 606 Not Acceptable ?*/
break;
case SalReasonNoMatch:
ret=481;
break;
case SalReasonRequestTimeout:
ret=408;
break;
case SalReasonMovedPermanently:
ret=301;
break;
case SalReasonGone:
ret=410;
break;
case SalReasonAddressIncomplete:
ret=484;
break;
case SalReasonNotImplemented:
ret=501;
break;
case SalReasonServerTimeout:
ret=504;
break;
case SalReasonBadGateway:
ret=502;
break;
case SalReasonInternalError:
ret=500;
break;
}
return ret;
}
#include "sal/sal.h"
SalReason _sal_reason_from_sip_code(int code) {
if (code>=100 && code<300) return SalReasonNone;
@ -561,13 +80,12 @@ SalReason _sal_reason_from_sip_code(int code) {
}
const SalErrorInfo *sal_error_info_none(void){
static SalErrorInfo none={
static const SalErrorInfo none = {
SalReasonNone,
(char *)"Ok",
200,
NULL,
NULL,
NULL
};
return &none;
}
@ -601,7 +119,7 @@ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol
else{
ei->reason=reason;
if (code == 0) {
code = sal_reason_to_sip_code(reason);
code = LinphonePrivate::to_sip_code(reason);
}
}
ei->protocol_code=code;
@ -614,290 +132,3 @@ void sal_error_info_set(SalErrorInfo *ei, SalReason reason, const char *protocol
else ei->full_string=ms_strdup(ei->status_string);
}
}
void sal_op_set_reason_error_info(SalOp *op, belle_sip_message_t *msg){
belle_sip_header_reason_t* reason_header = belle_sip_message_get_header_by_type(msg,belle_sip_header_reason_t);
if (reason_header){
SalErrorInfo *ei=&op->reason_error_info; // ?//
const char *protocol = belle_sip_header_reason_get_protocol(reason_header);
int code = belle_sip_header_reason_get_cause(reason_header);
const char *text = belle_sip_header_reason_get_text(reason_header);
sal_error_info_set(ei, SalReasonUnknown, protocol, code, text, NULL);
}
}
void sal_op_set_error_info_from_response(SalOp *op, belle_sip_response_t *response){
int code = belle_sip_response_get_status_code(response);
const char *reason_phrase=belle_sip_response_get_reason_phrase(response);
belle_sip_header_t *warning=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Warning");
SalErrorInfo *ei=&op->error_info;
const char *warnings;
warnings=warning ? belle_sip_header_get_unparsed_value(warning) : NULL;
sal_error_info_set(ei,SalReasonUnknown,"SIP", code,reason_phrase,warnings);
sal_op_set_reason_error_info(op, BELLE_SIP_MESSAGE(response));
}
const SalErrorInfo *sal_op_get_error_info(const SalOp *op){
return &op->error_info;
}
const SalErrorInfo * sal_op_get_reason_error_info(const SalOp *op){
return &op->reason_error_info;
}
static void unlink_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){
belle_sip_dialog_set_application_data(dialog,NULL);
sal_op_unref(op);
belle_sip_object_unref(dialog);
}
static belle_sip_dialog_t *link_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){
belle_sip_dialog_set_application_data(dialog,sal_op_ref(op));
belle_sip_object_ref(dialog);
return dialog;
}
void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) {
ms_message("op [%p] : set_or_update_dialog() current=[%p] new=[%p]",op,op->dialog,dialog);
sal_op_ref(op);
if (op->dialog!=dialog){
if (op->dialog){
/*FIXME: shouldn't we delete unconfirmed dialogs ?*/
unlink_op_with_dialog(op,op->dialog);
op->dialog=NULL;
}
if (dialog) {
op->dialog=link_op_with_dialog(op,dialog);
belle_sip_dialog_enable_pending_trans_checking(dialog,op->base.root->pending_trans_checking);
}
}
sal_op_unref(op);
}
/*return reffed op*/
SalOp* sal_op_ref(SalOp* op) {
op->ref++;
return op;
}
/*return null, destroy op if ref count =0*/
void* sal_op_unref(SalOp* op) {
op->ref--;
if (op->ref==0) {
sal_op_release_impl(op);
}else if (op->ref<0){
ms_fatal("SalOp [%p]: too many unrefs.",op);
}
return NULL;
}
int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ) {
if (sal_op_send_request_with_expires(op,req,expires)==0) {
if (op->refresher) {
belle_sip_refresher_stop(op->refresher);
belle_sip_object_unref(op->refresher);
}
if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) {
/*since refresher acquires the transaction, we should remove our context from the transaction, because we won't be notified
* that it is terminated anymore.*/
sal_op_unref(op);/*loose the reference that was given to the transaction when creating it*/
/* Note that the refresher will replace our data with belle_sip_transaction_set_application_data().
Something in the design is not very good here, it makes things complicated to the belle-sip user.
Possible ideas to improve things: refresher shall not use belle_sip_transaction_set_application_data() internally, refresher should let the first transaction
notify the user as a normal transaction*/
belle_sip_refresher_set_listener(op->refresher,listener,op);
belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after);
belle_sip_refresher_set_realm(op->refresher,op->base.realm);
belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher);
return 0;
} else {
return -1;
}
}
return -1;
}
const char* sal_op_state_to_string(const SalOpState value) {
switch(value) {
case SalOpStateEarly: return"SalOpStateEarly";
case SalOpStateActive: return "SalOpStateActive";
case SalOpStateTerminating: return "SalOpStateTerminating";
case SalOpStateTerminated: return "SalOpStateTerminated";
default:
return "Unknown";
}
}
/*
* Warning: this function takes owneship of the custom headers
*/
void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch){
SalOpBase *b=(SalOpBase *)op;
if (b->sent_custom_headers){
sal_custom_header_free(b->sent_custom_headers);
b->sent_custom_headers=NULL;
}
if (ch) belle_sip_object_ref((belle_sip_message_t*)ch);
b->sent_custom_headers=ch;
}
void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){
if (incoming) belle_sip_object_ref(incoming);
if (op->base.recv_custom_headers){
belle_sip_object_unref(op->base.recv_custom_headers);
op->base.recv_custom_headers=NULL;
}
if (incoming){
op->base.recv_custom_headers=(SalCustomHeader*)incoming;
}
}
const char *sal_op_get_remote_contact(const SalOp *op){
/*
* remote contact is filled in process_response
*/
return op->base.remote_contact;
}
SalBodyHandler * sal_op_get_body_handler(SalOp *op, belle_sip_message_t *msg) {
belle_sip_body_handler_t *body_handler = belle_sip_message_get_body_handler(msg);
if (body_handler != NULL) {
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t);
belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(msg, belle_sip_header_content_length_t);
belle_sip_header_t *content_encoding = belle_sip_message_get_header(msg, "Content-Encoding");
if (content_type != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_type));
if (content_length != NULL) belle_sip_body_handler_add_header(body_handler, BELLE_SIP_HEADER(content_length));
if (content_encoding != NULL) belle_sip_body_handler_add_header(body_handler, content_encoding);
}
return (SalBodyHandler *)body_handler;
}
void sal_op_set_privacy(SalOp* op,SalPrivacyMask privacy) {
op->privacy=privacy;
}
SalPrivacyMask sal_op_get_privacy(const SalOp* op) {
return op->privacy;
}
bool_t sal_op_is_secure(const SalOp* op) {
const SalAddress* from = sal_op_get_from_address(op);
const SalAddress* to = sal_op_get_to_address(op);
return from && to && strcasecmp("sips",sal_address_get_scheme(from))==0 && strcasecmp("sips",sal_address_get_scheme(to))==0;
}
void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled){
op->manual_refresher=enabled;
}
int sal_op_get_address_family(SalOp *op){
belle_sip_transaction_t *tr=NULL;
belle_sip_header_address_t *contact;
if (op->refresher)
tr=(belle_sip_transaction_t *)belle_sip_refresher_get_transaction(op->refresher);
if (tr==NULL)
tr=(belle_sip_transaction_t *)op->pending_client_trans;
if (tr==NULL)
tr=(belle_sip_transaction_t *)op->pending_server_trans;
if (tr==NULL){
bctbx_error("Unable to determine IP version from signaling operation.");
return AF_UNSPEC;
}
if (op->refresher) {
belle_sip_message_t *msg = belle_sip_transaction_get_response(tr) ? (belle_sip_message_t*) belle_sip_transaction_get_response(tr) : (belle_sip_message_t*) belle_sip_transaction_get_request(tr);
belle_sip_header_via_t *via = msg ?belle_sip_message_get_header_by_type(msg,belle_sip_header_via_t):NULL;
if (!via) {
bctbx_error("Unable to determine IP version from signaling operation, no via header found.");
return AF_UNSPEC;
}
const char *host = belle_sip_header_via_get_host(via);
if (!host) {
bctbx_error("Unable to get host. No network?");
return AF_UNSPEC;
}
return strchr(host, ':') ? AF_INET6 : AF_INET;
}
belle_sip_request_t *req = belle_sip_transaction_get_request(tr);
contact = (belle_sip_header_address_t *)belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t);
if (!contact)
bctbx_error("Unable to determine IP version from signaling operation, no contact header found.");
return sal_address_is_ipv6((SalAddress*)contact) ? AF_INET6 : AF_INET;
}
bool_t sal_op_is_idle(SalOp *op){
if (op->dialog){
return !belle_sip_dialog_request_pending(op->dialog);
}
return TRUE;
}
void sal_op_stop_refreshing(SalOp *op){
if (op->refresher){
belle_sip_refresher_stop(op->refresher);
}
}
void sal_call_set_sdp_handling(SalOp *h, SalOpSDPHandling handling) {
if (handling != SalOpSDPNormal) ms_message("Enabling special SDP handling for SalOp[%p]!", h);
h->sdp_handling = handling;
}
void sal_op_cnx_ip_to_0000_if_sendonly_enable(SalOp *op,bool_t yesno) {
op->cnx_ip_to_0000_if_sendonly_enabled = yesno;
}
bool_t sal_op_cnx_ip_to_0000_if_sendonly_enabled(SalOp *op) {
return op->cnx_ip_to_0000_if_sendonly_enabled;
}
bool_t sal_op_is_forked_of(const SalOp *op1, const SalOp *op2){
return op1->base.call_id && op2->base.call_id && strcmp(op1->base.call_id, op2->base.call_id) == 0;
}
int sal_op_refresh(SalOp *op) {
if (op->refresher) {
belle_sip_refresher_refresh(op->refresher,belle_sip_refresher_get_expires(op->refresher));
return 0;
}
ms_warning("sal_refresh on op [%p] of type [%s] no refresher",op,sal_op_type_to_string(op->type));
return -1;
}
void sal_op_set_event(SalOp *op, const char *eventname){
belle_sip_header_event_t *header = NULL;
if (op->event) belle_sip_object_unref(op->event);
if (eventname){
header = belle_sip_header_event_create(eventname);
belle_sip_object_ref(header);
}
op->event = header;
}
const char* sal_op_get_public_address(SalOp *op, int *port) {
if (op && op->refresher) {
return belle_sip_refresher_get_public_address(op->refresher, port);
}
return NULL;
}
const char* sal_op_get_local_address(SalOp *op, int *port) {
if (op && op->refresher) {
return belle_sip_refresher_get_local_address(op->refresher, port);
}
return NULL;
}
char* sal_op_get_dialog_id(const SalOp *op) {
if (op->dialog != NULL) {
return ms_strdup_printf("%s;to-tag=%s;from-tag=%s", ((SalOpBase*)op)->call_id,
belle_sip_dialog_get_remote_tag(op->dialog), belle_sip_dialog_get_local_tag(op->dialog));
}
return NULL;
}

View file

@ -1,34 +0,0 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications, Grenoble, France
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 "sal_impl.h"
int sal_send_info(SalOp *op, const char *from, const char *to, const SalBodyHandler *body_handler){
if (op->dialog && belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_CONFIRMED){
belle_sip_request_t *req;
belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking);
req=belle_sip_dialog_create_queued_request(op->dialog,"INFO");
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler));
return sal_op_send_request(op,req);
}else{
ms_error("Cannot send INFO message on op [%p] because dialog is not in confirmed state yet.", op);
}
return -1;
}

View file

@ -1,216 +0,0 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications, Grenoble, France
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 "sal_impl.h"
#include "linphone/core.h"
#include "private.h"
#include <libxml/xmlwriter.h>
static void process_error( SalOp* op) {
if (op->dir == SalOpDirOutgoing) {
op->base.root->callbacks.message_delivery_update(op, SalMessageDeliveryFailed);
} else {
ms_warning("unexpected io error for incoming message on op [%p]",op);
}
op->state=SalOpStateTerminated;
}
static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
SalOp* op = (SalOp*)user_ctx;
sal_error_info_set(&op->error_info,SalReasonIOError, "SIP", 503,"IO Error",NULL);
process_error(op);
}
static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
SalOp* op=(SalOp*)user_ctx;
sal_error_info_set(&op->error_info,SalReasonRequestTimeout, "SIP", 408,"Request timeout",NULL);
process_error(op);
}
static void process_response_event(void *op_base, const belle_sip_response_event_t *event){
SalOp* op = (SalOp*)op_base;
int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
SalMessageDeliveryStatus status;
sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event));
if (code>=100 && code <200)
status=SalMessageDeliveryInProgress;
else if (code>=200 && code <300)
status=SalMessageDeliveryDone;
else
status=SalMessageDeliveryFailed;
op->base.root->callbacks.message_delivery_update(op,status);
}
static bool_t is_external_body(belle_sip_header_content_type_t* content_type) {
return strcmp("message",belle_sip_header_content_type_get_type(content_type))==0
&& strcmp("external-body",belle_sip_header_content_type_get_subtype(content_type))==0;
}
static void add_message_accept(SalOp *op, belle_sip_message_t *msg) {
bctbx_list_t *item;
const char *str;
char *old;
char *header = ms_strdup("xml/cipher, application/cipher.vnd.gsma.rcs-ft-http+xml");
for (item = op->base.root->supported_content_types; item != NULL; item = bctbx_list_next(item)) {
str = (const char *)bctbx_list_get_data(item);
old = header;
header = ms_strdup_printf("%s, %s", old, str);
ms_free(old);
}
belle_sip_message_add_header(msg, belle_sip_header_create("Accept", header));
ms_free(header);
}
void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req);
belle_sip_header_address_t* address;
belle_sip_header_from_t* from_header;
belle_sip_header_content_type_t* content_type;
belle_sip_response_t* resp;
int errcode = 500;
belle_sip_header_call_id_t* call_id = belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t);
belle_sip_header_cseq_t* cseq = belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(req,belle_sip_header_date_t);
char* from;
bool_t external_body=FALSE;
from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t);
if (content_type) {
SalMessage salmsg;
char message_id[256]={0};
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
op->pending_server_trans=server_transaction;
belle_sip_object_ref(op->pending_server_trans);
external_body=is_external_body(content_type);
address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header))
,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header)));
from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address));
snprintf(message_id,sizeof(message_id)-1,"%s%i"
,belle_sip_header_call_id_get_call_id(call_id)
,belle_sip_header_cseq_get_seq_number(cseq));
salmsg.from=from;
/* if we just deciphered a message, use the deciphered part(which can be a rcs xml body pointing to the file to retreive from server)*/
salmsg.text=(!external_body)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL;
salmsg.url=NULL;
salmsg.content_type = ms_strdup_printf("%s/%s", belle_sip_header_content_type_get_type(content_type), belle_sip_header_content_type_get_subtype(content_type));
if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) {
size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL"));
salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/
((char*)salmsg.url)[url_length-2]='\0'; /*remove trailing "*/
}
salmsg.message_id=message_id;
salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL);
op->base.root->callbacks.message_received(op,&salmsg);
belle_sip_object_unref(address);
belle_sip_free(from);
if (salmsg.url) ms_free((char*)salmsg.url);
ms_free((char *)salmsg.content_type);
} else {
ms_error("Unsupported MESSAGE (no Content-Type)");
resp = belle_sip_response_create_from_request(req, errcode);
add_message_accept(op, (belle_sip_message_t*)resp);
belle_sip_server_transaction_send_response(server_transaction,resp);
sal_op_release(op);
}
}
static void process_request_event(void *op_base, const belle_sip_request_event_t *event) {
SalOp* op = (SalOp*)op_base;
sal_process_incoming_message(op,event);
}
int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg, const char *peer_uri){
belle_sip_request_t* req;
char content_type_raw[256];
size_t content_length = msg?strlen(msg):0;
time_t curtime = ms_time(NULL);
const char *body;
int retval;
if (op->dialog){
/*for SIP MESSAGE that are sent in call's dialog*/
req=belle_sip_dialog_create_queued_request(op->dialog,"MESSAGE");
}else{
sal_op_message_fill_cbs(op);
if (from)
sal_op_set_from(op,from);
if (to)
sal_op_set_to(op,to);
op->dir=SalOpDirOutgoing;
req=sal_op_build_request(op,"MESSAGE");
if (req == NULL ){
return -1;
}
if (sal_op_get_contact_address(op)){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
}
}
snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime)));
body = msg;
if (body){
/*don't call set_body() with null argument because it resets content type and content length*/
belle_sip_message_set_body(BELLE_SIP_MESSAGE(req), body, content_length);
}
retval = sal_op_send_request(op,req);
return retval;
}
int sal_message_reply(SalOp *op, SalReason reason){
if (op->pending_server_trans){
int code=sal_reason_to_sip_code(reason);
belle_sip_response_t *resp = belle_sip_response_create_from_request(
belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_server_trans),code);
belle_sip_server_transaction_send_response(op->pending_server_trans,resp);
return 0;
}else ms_error("sal_message_reply(): no server transaction");
return -1;
}
int sal_text_send(SalOp *op, const char *from, const char *to, const char *msg) {
return sal_message_send(op,from,to,"text/plain",msg, NULL);
}
static belle_sip_listener_callbacks_t op_message_callbacks={0};
void sal_op_message_fill_cbs(SalOp*op) {
if (op_message_callbacks.process_io_error==NULL){
op_message_callbacks.process_io_error=process_io_error;
op_message_callbacks.process_response_event=process_response_event;
op_message_callbacks.process_timeout=process_timeout;
op_message_callbacks.process_request_event=process_request_event;
}
op->callbacks=&op_message_callbacks;
op->type=SalOpMessage;
}

View file

@ -1,441 +0,0 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications, Grenoble, France
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 "sal_impl.h"
void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceModel *presence) {
char *contact_info;
char *content = NULL;
size_t content_length;
if (presence){
belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(notify,belle_sip_header_from_t);
contact_info=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from)));
op->base.root->callbacks.convert_presence_to_xml_requested(op, presence, contact_info, &content);
belle_sip_free(contact_info);
if (content == NULL) return;
}
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_TYPE);
belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_LENGTH);
belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),NULL,0);
if (content){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","pidf+xml")));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(content))));
belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),content,content_length);
ms_free(content);
}
}
static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
SalOp* op = (SalOp*)user_ctx;
belle_sip_request_t* request;
belle_sip_client_transaction_t* client_transaction = NULL;
if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(belle_sip_io_error_event_get_source(event),
belle_sip_client_transaction_t)){
client_transaction = (belle_sip_client_transaction_t*)belle_sip_io_error_event_get_source(event);
}
if (!client_transaction) return;
request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0){
if (op->refresher){
ms_warning("presence_process_io_error() refresher is present, should not happen");
return;
}
ms_message("subscription to [%s] io error",sal_op_get_to(op));
if (!op->op_released){
op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/
}
}
}
static void presence_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) {
SalOp* op= (SalOp*)ctx;
if (op->dialog && belle_sip_dialog_is_server(op->dialog)) {
ms_message("Incoming subscribtion from [%s] terminated",sal_op_get_from(op));
if (!op->op_released){
op->base.root->callbacks.subscribe_presence_closed(op, sal_op_get_from(op));
}
set_or_update_dialog(op, NULL);
}/* else client dialog is managed by refresher*/
}
static void presence_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase, int will_retry){
SalOp* op = (SalOp*)user_pointer;
if (status_code >= 300) {
ms_message("The SUBSCRIBE dialog no longer works. Let's restart a new one.");
belle_sip_refresher_stop(op->refresher);
if (op->dialog) { /*delete previous dialog if any*/
set_or_update_dialog(op, NULL);
}
if (sal_op_get_contact_address(op)) {
/*contact is also probably not good*/
SalAddress* contact=sal_address_clone(sal_op_get_contact_address(op));
sal_address_set_port(contact,-1);
sal_address_set_domain(contact,NULL);
sal_op_set_contact_address(op,contact);
sal_address_destroy(contact);
}
/*send a new SUBSCRIBE, that will attempt to establish a new dialog*/
sal_subscribe_presence(op,NULL,NULL,-1);
}
if (status_code == 0 || status_code == 503){
/*timeout or io error: the remote doesn't seem reachable.*/
if (!op->op_released){
op->base.root->callbacks.notify_presence(op,SalSubscribeActive, NULL,NULL); /*NULL = offline*/
}
}
}
static void presence_response_event(void *op_base, const belle_sip_response_event_t *event){
SalOp* op = (SalOp*)op_base;
belle_sip_dialog_state_t dialog_state;
belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
belle_sip_response_t* response=belle_sip_response_event_get_response(event);
belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
int code = belle_sip_response_get_status_code(response);
belle_sip_header_expires_t* expires;
sal_op_set_error_info_from_response(op,response);
if (code>=300) {
if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0){
ms_message("subscription to [%s] rejected",sal_op_get_to(op));
if (!op->op_released){
op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/
}
return;
}
}
set_or_update_dialog(reinterpret_cast<SalOp *>(op_base),belle_sip_response_event_get_dialog(event));
if (!op->dialog) {
ms_message("presence op [%p] receive out of dialog answer [%i]",op,code);
return;
}
dialog_state=belle_sip_dialog_get_state(op->dialog);
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL:
case BELLE_SIP_DIALOG_EARLY: {
ms_error("presence op [%p] receive an unexpected answer [%i]",op,code);
break;
}
case BELLE_SIP_DIALOG_CONFIRMED: {
if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0) {
expires=belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t);
if(op->refresher) {
belle_sip_refresher_stop(op->refresher);
belle_sip_object_unref(op->refresher);
op->refresher=NULL;
}
if ((expires != NULL) && (belle_sip_header_expires_get_expires(expires) > 0)) {
op->refresher=belle_sip_client_transaction_create_refresher(client_transaction);
belle_sip_refresher_set_listener(op->refresher,presence_refresher_listener,op);
belle_sip_refresher_set_realm(op->refresher,op->base.realm);
}
}
break;
}
default: {
ms_error("presence op [%p] receive answer [%i] not implemented",op,code);
}
/* no break */
}
}
static void presence_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
SalOp* op = (SalOp*)user_ctx;
belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event);
belle_sip_request_t* request;
if (!client_transaction) return;
request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0){
ms_message("subscription to [%s] timeout",sal_op_get_to(op));
if (!op->op_released){
op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/
}
}
}
static void presence_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
ms_message("presence_process_transaction_terminated not implemented yet");
}
static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_request_t *req) {
belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_type_t);
belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_length_t);
const char *body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
SalPresenceModel *result = NULL;
if ((content_type == NULL) || (content_length == NULL))
return NULL;
if (belle_sip_header_content_length_get_content_length(content_length) == 0)
return NULL;
if (body==NULL) return NULL;
if (!op->op_released){
op->base.root->callbacks.parse_presence_requested(op,
belle_sip_header_content_type_get_type(content_type),
belle_sip_header_content_type_get_subtype(content_type),
body,
&result);
}
return result;
}
static void handle_notify(SalOp *op, belle_sip_request_t *req, belle_sip_dialog_t *dialog){
belle_sip_response_t* resp=NULL;
belle_sip_server_transaction_t* server_transaction=op->pending_server_trans;
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t);
SalSubscribeStatus sub_state;
if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) {
SalPresenceModel *presence_model = NULL;
const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
if (op->dialog !=NULL && dialog != op->dialog){
ms_warning("Receiving a NOTIFY from a dialog we haven't stored (op->dialog=%p dialog=%p)", op->dialog, dialog);
}
if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) {
sub_state=SalSubscribeTerminated;
ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op));
} else {
sub_state=belle_sip_message_get_subscription_state(BELLE_SIP_MESSAGE(req));
}
presence_model = process_presence_notification(op, req);
if (presence_model != NULL || body==NULL) {
/* Presence notification body parsed successfully. */
resp = sal_op_create_response_from_request(op, req, 200); /*create first because the op may be destroyed by notify_presence */
if (!op->op_released){
op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL);
}
} else if (body){
/* Formatting error in presence notification body. */
ms_warning("Wrongly formatted presence document.");
resp = sal_op_create_response_from_request(op, req, 488);
}
if (resp) belle_sip_server_transaction_send_response(server_transaction,resp);
}
}
static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) {
SalOp* op = (SalOp*)op_base;
belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
belle_sip_request_t* req = belle_sip_request_event_get_request(event);
belle_sip_dialog_state_t dialog_state;
belle_sip_response_t* resp;
const char *method=belle_sip_request_get_method(req);
belle_sip_header_event_t *event_header;
belle_sip_object_ref(server_transaction);
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
op->pending_server_trans=server_transaction;
event_header=belle_sip_message_get_header_by_type(req,belle_sip_header_event_t);
if (event_header==NULL){
ms_warning("No event header in incoming SUBSCRIBE.");
resp=sal_op_create_response_from_request(op,req,400);
belle_sip_server_transaction_send_response(server_transaction,resp);
if (!op->dialog) sal_op_release(op);
return;
}
if (op->event==NULL) {
op->event=event_header;
belle_sip_object_ref(op->event);
}
if (!op->dialog) {
if (strcmp(method,"SUBSCRIBE")==0){
belle_sip_dialog_t *dialog = belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction));
if (!dialog){
resp=sal_op_create_response_from_request(op,req,481);
belle_sip_server_transaction_send_response(server_transaction,resp);
sal_op_release(op);
return;
}
set_or_update_dialog(op, dialog);
ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
}else if (strcmp(method,"NOTIFY")==0 && belle_sip_request_event_get_dialog(event)) {
/*special case of dialog created by notify matching subscribe*/
set_or_update_dialog(op, belle_sip_request_event_get_dialog(event));
} else {/* this is a NOTIFY */
ms_message("Receiving out of dialog notify");
handle_notify(op, req, belle_sip_request_event_get_dialog(event));
return;
}
}
dialog_state=belle_sip_dialog_get_state(op->dialog);
switch(dialog_state) {
case BELLE_SIP_DIALOG_NULL: {
if (strcmp("NOTIFY",method)==0) {
handle_notify(op, req, belle_sip_request_event_get_dialog(event));
} else if (strcmp("SUBSCRIBE",method)==0) {
op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op));
}
break;
}
case BELLE_SIP_DIALOG_EARLY:
ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",method,op->dialog);
break;
case BELLE_SIP_DIALOG_CONFIRMED:
if (strcmp("NOTIFY",method)==0) {
handle_notify(op, req, belle_sip_request_event_get_dialog(event));
} else if (strcmp("SUBSCRIBE",method)==0) {
/*either a refresh or an unsubscribe.
If it is a refresh there is nothing to notify to the app. If it is an unSUBSCRIBE, then the dialog
will be terminated shortly, and this will be notified to the app through the dialog_terminated callback.*/
resp=sal_op_create_response_from_request(op,req,200);
belle_sip_server_transaction_send_response(server_transaction,resp);
}
break;
default:
ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state));
break;
}
}
static belle_sip_listener_callbacks_t op_presence_callbacks={0};
/*Invoke when sal_op_release is called by upper layer*/
static void sal_op_release_cb(struct SalOpBase* op_base) {
SalOp *op =(SalOp*)op_base;
if(op->refresher) {
belle_sip_refresher_stop(op->refresher);
belle_sip_object_unref(op->refresher);
op->refresher=NULL;
set_or_update_dialog(op,NULL); /*only if we have refresher. else dialog terminated event will remove association*/
}
}
void sal_op_presence_fill_cbs(SalOp*op) {
if (op_presence_callbacks.process_request_event==NULL){
op_presence_callbacks.process_io_error=presence_process_io_error;
op_presence_callbacks.process_response_event=presence_response_event;
op_presence_callbacks.process_timeout=presence_process_timeout;
op_presence_callbacks.process_transaction_terminated=presence_process_transaction_terminated;
op_presence_callbacks.process_request_event=presence_process_request_event;
op_presence_callbacks.process_dialog_terminated=presence_process_dialog_terminated;
}
op->callbacks=&op_presence_callbacks;
op->type=SalOpPresence;
op->base.release_cb=sal_op_release_cb;
}
/*presence Subscribe/notify*/
int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expires){
belle_sip_request_t *req=NULL;
if (from)
sal_op_set_from(op,from);
if (to)
sal_op_set_to(op,to);
sal_op_presence_fill_cbs(op);
if (expires==-1){
if (op->refresher){
expires=belle_sip_refresher_get_expires(op->refresher);
belle_sip_object_unref(op->refresher);
op->refresher=NULL;
}else{
ms_error("sal_subscribe_presence(): cannot guess expires from previous refresher.");
return -1;
}
}
if (!op->event){
op->event=belle_sip_header_event_create("presence");
belle_sip_object_ref(op->event);
}
belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.from_address),"tag");
belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.to_address),"tag");
req=sal_op_build_request(op,"SUBSCRIBE");
if( req ){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(op->event));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
}
return sal_op_send_request(op,req);
}
static belle_sip_request_t *create_presence_notify(SalOp *op){
belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY");
if (!notify) return NULL;
belle_sip_message_add_header((belle_sip_message_t*)notify,belle_sip_header_create("Event","presence"));
return notify;
}
static int sal_op_check_dialog_state(SalOp *op) {
belle_sip_dialog_state_t state=op->dialog?belle_sip_dialog_get_state(op->dialog): BELLE_SIP_DIALOG_NULL;
if (state != BELLE_SIP_DIALOG_CONFIRMED) {
ms_warning("Cannot notify presence for op [%p] because dialog in state [%s]",op, belle_sip_dialog_state_to_string(state));
return -1;
} else
return 0;
}
int sal_notify_presence(SalOp *op, SalPresenceModel *presence){
belle_sip_request_t* notify=NULL;
if (sal_op_check_dialog_state(op)) {
return -1;
}
notify=create_presence_notify(op);
if (!notify) return-1;
sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),presence); /*FIXME, what about expires ??*/
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600)));
return sal_op_send_request(op,notify);
}
int sal_notify_presence_close(SalOp *op){
belle_sip_request_t* notify=NULL;
int status;
if (sal_op_check_dialog_state(op)) {
return -1;
}
notify=create_presence_notify(op);
if (!notify) return-1;
sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),NULL); /*FIXME, what about expires ??*/
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1)));
status = sal_op_send_request(op,notify);
set_or_update_dialog(op,NULL); /*because we may be chalanged for the notify, so we must release dialog right now*/
return status;
}

View file

@ -1,112 +0,0 @@
/*
linphone
Copyright (C) 2012 Belledonne Communications, Grenoble, France
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 "sal_impl.h"
static void publish_refresher_listener (belle_sip_refresher_t* refresher
,void* user_pointer
,unsigned int status_code
,const char* reason_phrase, int will_retry) {
SalOp* op = (SalOp*)user_pointer;
const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
belle_sip_response_t *response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(last_publish_trans));
ms_message("Publish refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",sal_op_get_proxy(op));
if (status_code==0){
op->base.root->callbacks.on_expire(op);
}else if (status_code>=200){
belle_sip_header_t *sip_etag;
const char *sip_etag_string = NULL;
if (response && (sip_etag = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response), "SIP-ETag"))) {
sip_etag_string = belle_sip_header_get_unparsed_value(sip_etag);
}
sal_op_set_entity_tag(op, sip_etag_string);
sal_error_info_set(&op->error_info,SalReasonUnknown, "SIP", status_code,reason_phrase,NULL);
sal_op_assign_recv_headers(op,(belle_sip_message_t*)response);
op->base.root->callbacks.on_publish_response(op);
}
}
static void publish_response_event(void *userctx, const belle_sip_response_event_t *event){
SalOp *op=(SalOp*)userctx;
sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event));
if (op->error_info.protocol_code>=200){
op->base.root->callbacks.on_publish_response(op);
}
}
static belle_sip_listener_callbacks_t op_publish_callbacks={0};
void sal_op_publish_fill_cbs(SalOp *op) {
if (op_publish_callbacks.process_response_event==NULL){
op_publish_callbacks.process_response_event=publish_response_event;
}
op->callbacks=&op_publish_callbacks;
op->type=SalOpPublish;
}
int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBodyHandler *body_handler){
belle_sip_request_t *req=NULL;
if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) {
if (from)
sal_op_set_from(op,from);
if (to)
sal_op_set_to(op,to);
sal_op_publish_fill_cbs(op);
req=sal_op_build_request(op,"PUBLISH");
if( req == NULL ){
return -1;
}
if (sal_op_get_entity_tag(op)) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("SIP-If-Match", sal_op_get_entity_tag(op)));
}
if (sal_op_get_contact_address(op)){
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
}
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname));
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), BELLE_SIP_BODY_HANDLER(body_handler));
if (expires!=-1)
return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener);
else return sal_op_send_request(op,req);
} else {
/*update status*/
const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
/*update body*/
if (expires == 0) {
belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_publish), NULL, 0);
} else {
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(last_publish), BELLE_SIP_BODY_HANDLER(body_handler));
}
return belle_sip_refresher_refresh(op->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires);
}
}
int sal_op_unpublish(SalOp *op){
if (op->refresher){
const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
belle_sip_message_set_body(BELLE_SIP_MESSAGE(last_req), NULL, 0);
belle_sip_refresher_refresh(op->refresher,0);
return 0;
}
return -1;
}

View file

@ -42,7 +42,7 @@ static void add_ice_candidates(belle_sdp_media_description_t *md, const SalStrea
return;
}
if (candidate->raddr[0] != '\0') {
nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport);
nb = snprintf(buffer + nb, sizeof(buffer) - (size_t)nb, " raddr %s rport %d", candidate->raddr, candidate->rport);
if (nb < 0) {
ms_error("Cannot add ICE candidate attribute!");
return;
@ -63,7 +63,7 @@ static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const S
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) {
candidate = &desc->ice_remote_candidates[i];
if ((candidate->addr[0] != '\0') && (candidate->port != 0)) {
offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port);
offset = snprintf(ptr, (size_t)(buffer + sizeof(buffer) - ptr), "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port);
if (offset < 0) {
ms_error("Cannot add ICE remote-candidates attribute!");
return;
@ -150,25 +150,25 @@ static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, co
/* Add trr-int if not set generally. */
if (general_trr_int != TRUE && trr_int != 0) {
add_rtcp_fb_trr_int_attribute(media_desc, payload_type_get_number(pt), avpf_params.trr_interval);
add_rtcp_fb_trr_int_attribute(media_desc, (int8_t)payload_type_get_number(pt), avpf_params.trr_interval);
}
/* Add rtcp-fb attributes according to the AVPF features of the payload types. */
if (avpf_params.features & PAYLOAD_TYPE_AVPF_PLI) {
add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI);
add_rtcp_fb_nack_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI);
}
if (avpf_params.features & PAYLOAD_TYPE_AVPF_SLI) {
add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI);
add_rtcp_fb_nack_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI);
}
if (avpf_params.features & PAYLOAD_TYPE_AVPF_RPSI) {
if (avpf_params.rpsi_compatibility == TRUE) {
add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI);
add_rtcp_fb_nack_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI);
} else {
add_rtcp_fb_ack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI);
add_rtcp_fb_ack_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI);
}
}
if (avpf_params.features & PAYLOAD_TYPE_AVPF_FIR) {
add_rtcp_fb_ccm_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_FIR);
add_rtcp_fb_ccm_attribute(media_desc, (int8_t)payload_type_get_number(pt), BELLE_SDP_RTCP_FB_FIR);
}
}
}
@ -263,9 +263,9 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
if (ms_crypto_suite_to_name_params(stream->crypto[j].algo,&desc)==0){
if (desc.params)
snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s %s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key,desc.params);
else
else
snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key );
belle_sdp_media_description_add_attribute( media_desc,belle_sdp_attribute_create ("crypto", buffer));
}else break;
}
@ -314,11 +314,11 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
break;
}
if ( dir ) belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( dir,NULL ) );
if (stream->rtcp_mux){
belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create ("rtcp-mux",NULL ) );
}
if (rtp_port != 0) {
different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0);
if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) {
@ -337,7 +337,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-mismatch",NULL));
} else {
if (rtp_port != 0) {
if (stream->ice_pwd[0] != '\0')
if (stream->ice_pwd[0] != '\0')
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-pwd",stream->ice_pwd));
if (stream->ice_ufrag[0] != '\0')
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-ufrag",stream->ice_ufrag));
@ -432,7 +432,7 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
if ( desc->bandwidth>0 ) {
belle_sdp_session_description_set_bandwidth ( session_desc,"AS",desc->bandwidth );
}
if (desc->set_nortpproxy == TRUE) belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("nortpproxy","yes"));
if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd));
if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag));
@ -486,7 +486,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S
static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
belle_sip_list_t *attribute_it;
belle_sdp_attribute_t *attribute;
char tmp[256], tmp2[256], parameters[256]={0};
char tmp[257], tmp2[257], parameters[257]={0};
int valid_count = 0;
int nb;
@ -501,7 +501,7 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med
&stream->crypto[valid_count].tag,
tmp,
tmp2, parameters );
if ( nb >= 3 ) {
MSCryptoSuite cs;
MSCryptoSuiteNameParams np;
@ -651,7 +651,7 @@ static bool_t sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_
PayloadType *pt;
int8_t pt_num;
bool_t retval = FALSE;
/* Handle rtcp-fb attributes that concern all payload types. */
for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) {
attribute = BELLE_SDP_ATTRIBUTE(it->data);
@ -805,7 +805,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
}
stream->rtcp_mux = belle_sdp_media_description_get_attribute(media_desc, "rtcp-mux") != NULL;
/* Get media payload types */
sdp_parse_payload_types(media_desc, stream);
@ -857,7 +857,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md,
/* Get ICE candidate attributes if any */
sdp_parse_media_ice_parameters(media_desc, stream);
has_avpf_attributes = sdp_parse_rtcp_fb_parameters(media_desc, stream);
/* Get RTCP-FB attributes if any */
@ -892,7 +892,7 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S
const char* value;
SalDtlsRole session_role=SalDtlsRoleInvalid;
int i;
desc->nb_streams = 0;
desc->dir = SalStreamSendRecv;
@ -902,11 +902,11 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S
if ( (sname=belle_sdp_session_description_get_session_name(session_desc)) && belle_sdp_session_name_get_value(sname) ){
strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name) - 1);
}
if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) {
desc->bandwidth=belle_sdp_session_description_get_bandwidth ( session_desc,"AS" );
}
/*in some very rare case, session attribute may set stream dir*/
if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) {
desc->dir=SalStreamSendRecv;
@ -940,10 +940,10 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S
/* Get ICE remote ufrag and remote pwd, and ice_lite flag */
value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag");
if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1);
value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd");
if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)-1);
value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite");
if (value) desc->ice_lite = TRUE;

View file

@ -18,10 +18,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/core.h"
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
static void linphone_buffer_destroy(LinphoneBuffer *buffer) {
if (buffer->content) belle_sip_free(buffer->content);
}

View file

@ -16,27 +16,29 @@ 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 __APPLE__
#ifndef __APPLE__ /*XOPEN_SOURCE icompilation issue with xcode9 https://github.com/eclipse/omr/pull/1721*/
#define _XOPEN_SOURCE 700 /*required for strptime of GNU libc*/
#endif
#include <time.h>
#include "private.h"
#ifdef SQLITE_STORAGE_ENABLED
#ifndef _WIN32
#if !defined(__ANDROID__) && !defined(__QNXNTO__)
# include <langinfo.h>
# include <iconv.h>
# include <string.h>
#endif
#else
#include <Windows.h>
#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__QNXNTO__)
#include <langinfo.h>
#include <iconv.h>
#include <string.h>
#endif
#include "sqlite3.h"
#define MAX_PATH_SIZE 1024
#endif
#define MAX_PATH_SIZE 1024
#include "sqlite3.h"
#endif
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
typedef struct _CallLogStorageResult {
LinphoneCore *core;
@ -117,7 +119,7 @@ void call_logs_write_to_config_file(LinphoneCore *lc){
}
}
bctbx_list_t * call_logs_read_from_config_file(LinphoneCore *lc){
bctbx_list_t * linphone_core_read_call_logs_from_config_file(LinphoneCore *lc){
char logsection[32];
int i;
const char *tmp;
@ -138,7 +140,7 @@ bctbx_list_t * call_logs_read_from_config_file(LinphoneCore *lc){
continue;
cl=linphone_call_log_new(static_cast<LinphoneCallDir>(lp_config_get_int(cfg,logsection,"dir",0)),from,to);
cl->status=static_cast<LinphoneCallStatus>(lp_config_get_int(cfg,logsection,"status",0));
sec=lp_config_get_int64(cfg,logsection,"start_date_time",0);
sec=(uint64_t)lp_config_get_int64(cfg,logsection,"start_date_time",0);
if (sec) {
/*new call log format with date expressed in seconds */
cl->start_date_time=(time_t)sec;
@ -154,7 +156,7 @@ bctbx_list_t * call_logs_read_from_config_file(LinphoneCore *lc){
tmp=lp_config_get_string(cfg,logsection,"refkey",NULL);
if (tmp) cl->refkey=ms_strdup(tmp);
cl->quality=lp_config_get_float(cfg,logsection,"quality",-1);
cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0);
cl->video_enabled=!!lp_config_get_int(cfg,logsection,"video_enabled",0);
tmp=lp_config_get_string(cfg,logsection,"call_id",NULL);
if (tmp) cl->call_id=ms_strdup(tmp);
call_logs=bctbx_list_append(call_logs,cl);
@ -189,15 +191,15 @@ const char *linphone_call_log_get_call_id(const LinphoneCallLog *cl){
return cl->call_id;
}
LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl){
LinphoneCallDir linphone_call_log_get_dir(const LinphoneCallLog *cl){
return cl->dir;
}
int linphone_call_log_get_duration(LinphoneCallLog *cl){
int linphone_call_log_get_duration(const LinphoneCallLog *cl){
return cl->duration;
}
LinphoneAddress *linphone_call_log_get_from_address(LinphoneCallLog *cl){
const LinphoneAddress *linphone_call_log_get_from_address(const LinphoneCallLog *cl){
return cl->from;
}
@ -205,7 +207,7 @@ const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl){
return &cl->local_stats;
}
float linphone_call_log_get_quality(LinphoneCallLog *cl){
float linphone_call_log_get_quality(const LinphoneCallLog *cl){
return cl->quality;
}
@ -213,7 +215,11 @@ const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl){
return cl->refkey;
}
LinphoneAddress *linphone_call_log_get_remote_address(LinphoneCallLog *cl){
const LinphoneAddress *linphone_call_log_get_local_address(const LinphoneCallLog *cl) {
return (cl->dir == LinphoneCallIncoming) ? cl->to : cl->from;
}
const LinphoneAddress *linphone_call_log_get_remote_address(const LinphoneCallLog *cl){
return (cl->dir == LinphoneCallIncoming) ? cl->from : cl->to;
}
@ -221,15 +227,15 @@ const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl)
return &cl->remote_stats;
}
time_t linphone_call_log_get_start_date(LinphoneCallLog *cl){
time_t linphone_call_log_get_start_date(const LinphoneCallLog *cl){
return cl->start_date_time;
}
LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl){
LinphoneCallStatus linphone_call_log_get_status(const LinphoneCallLog *cl){
return cl->status;
}
LinphoneAddress *linphone_call_log_get_to_address(LinphoneCallLog *cl){
const LinphoneAddress *linphone_call_log_get_to_address(const LinphoneCallLog *cl){
return cl->to;
}
@ -241,32 +247,32 @@ void linphone_call_log_set_ref_key(LinphoneCallLog *cl, const char *refkey){
if (refkey) cl->refkey=ms_strdup(refkey);
}
char * linphone_call_log_to_str(LinphoneCallLog *cl){
char * linphone_call_log_to_str(const LinphoneCallLog *cl){
const char *status;
char *tmp;
char *from=linphone_address_as_string (cl->from);
char *to=linphone_address_as_string (cl->to);
switch(cl->status){
case LinphoneCallAborted:
status=_("aborted");
status="aborted";
break;
case LinphoneCallSuccess:
status=_("completed");
status="completed";
break;
case LinphoneCallMissed:
status=_("missed");
status="missed";
break;
case LinphoneCallAcceptedElsewhere:
status=_("answered elsewhere");
status="answered elsewhere";
break;
case LinphoneCallDeclinedElsewhere:
status=_("declined elsewhere");
status="declined elsewhere";
break;
default:
status=_("unknown");
status="unknown";
}
tmp=ms_strdup_printf(_("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n"),
(cl->dir==LinphoneCallIncoming) ? _("Incoming call") : _("Outgoing call"),
tmp=ms_strdup_printf("%s at %s\nFrom: %s\nTo: %s\nStatus: %s\nDuration: %i mn %i sec\n",
(cl->dir==LinphoneCallIncoming) ? "Incoming call" : "Outgoing call",
cl->start_date,
from,
to,
@ -278,15 +284,15 @@ char * linphone_call_log_to_str(LinphoneCallLog *cl){
return tmp;
}
bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl) {
bool_t linphone_call_log_video_enabled(const LinphoneCallLog *cl) {
return cl->video_enabled;
}
bool_t linphone_call_log_was_conference(LinphoneCallLog *cl) {
bool_t linphone_call_log_was_conference(const LinphoneCallLog *cl) {
return cl->was_conference;
}
const LinphoneErrorInfo *linphone_call_log_get_error_info(LinphoneCallLog *cl){
const LinphoneErrorInfo *linphone_call_log_get_error_info(const LinphoneCallLog *cl){
return cl->error_info;
}
@ -334,7 +340,7 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCallDir dir, LinphoneAddress *fr
set_call_log_date(cl,cl->start_date_time);
cl->from=from;
cl->to=to;
cl->to=to;
cl->status=LinphoneCallAborted; /*default status*/
cl->quality=-1;
@ -579,7 +585,7 @@ const bctbx_list_t *linphone_core_get_call_history(LinphoneCore *lc) {
CallLogStorageResult clsres;
if (!lc || lc->logs_db == NULL) return NULL;
if (lc->call_logs != NULL) return lc->call_logs;
if (lc->call_logs != NULL) return lc->call_logs;
if (lc->max_call_logs != LINPHONE_MAX_CALL_HISTORY_UNLIMITED){
buf = sqlite3_mprintf("SELECT * FROM call_history ORDER BY id DESC LIMIT %i", lc->max_call_logs);
@ -625,7 +631,10 @@ int linphone_core_get_call_history_size(LinphoneCore *lc) {
sqlite3_stmt *selectStatement;
int returnValue;
if (!lc || lc->logs_db == NULL) return 0;
if (!lc)
return 0;
if (!lc->logs_db)
return (int)bctbx_list_size(lc->call_logs);
buf = sqlite3_mprintf("SELECT count(*) FROM call_history");
returnValue = sqlite3_prepare_v2(lc->logs_db, buf, -1, &selectStatement, NULL);

View file

@ -1,408 +0,0 @@
/*
linphone
Copyright (C) 2010-2014 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/call_params.h"
#include "private.h"
/*******************************************************************************
* Internal functions *
******************************************************************************/
SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) {
if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf;
if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp;
if ((params->media_encryption == LinphoneMediaEncryptionDTLS) && params->avpf_enabled) return SalProtoUdpTlsRtpSavpf;
if (params->media_encryption == LinphoneMediaEncryptionDTLS) return SalProtoUdpTlsRtpSavp;
if (params->avpf_enabled) return SalProtoRtpAvpf;
return SalProtoRtpAvp;
}
SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir) {
switch (cpdir) {
case LinphoneMediaDirectionInactive:
return SalStreamInactive;
case LinphoneMediaDirectionSendOnly:
return SalStreamSendOnly;
case LinphoneMediaDirectionRecvOnly:
return SalStreamRecvOnly;
case LinphoneMediaDirectionSendRecv:
return SalStreamSendRecv;
case LinphoneMediaDirectionInvalid:
ms_error("LinphoneMediaDirectionInvalid shall not be used.");
return SalStreamInactive;
}
return SalStreamSendRecv;
}
LinphoneMediaDirection media_direction_from_sal_stream_dir(SalStreamDir dir){
switch (dir) {
case SalStreamInactive:
return LinphoneMediaDirectionInactive;
case SalStreamSendOnly:
return LinphoneMediaDirectionSendOnly;
case SalStreamRecvOnly:
return LinphoneMediaDirectionRecvOnly;
case SalStreamSendRecv:
return LinphoneMediaDirectionSendRecv;
}
return LinphoneMediaDirectionSendRecv;
}
SalStreamDir get_audio_dir_from_call_params(const LinphoneCallParams *params) {
return sal_dir_from_call_params_dir(linphone_call_params_get_audio_direction(params));
}
SalStreamDir get_video_dir_from_call_params(const LinphoneCallParams *params) {
return sal_dir_from_call_params_dir(linphone_call_params_get_video_direction(params));
}
void linphone_call_params_set_custom_headers(LinphoneCallParams *params, const SalCustomHeader *ch){
if (params->custom_headers){
sal_custom_header_free(params->custom_headers);
params->custom_headers = NULL;
}
if (ch){
params->custom_headers = sal_custom_header_clone(ch);
}
}
void linphone_call_params_set_custom_sdp_attributes(LinphoneCallParams *params, const SalCustomSdpAttribute *csa) {
if (params->custom_sdp_attributes) {
sal_custom_sdp_attribute_free(params->custom_sdp_attributes);
params->custom_sdp_attributes = NULL;
}
if (csa) {
params->custom_sdp_attributes = sal_custom_sdp_attribute_clone(csa);
}
}
void linphone_call_params_set_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type, const SalCustomSdpAttribute *csa) {
if (params->custom_sdp_media_attributes[type]) {
sal_custom_sdp_attribute_free(params->custom_sdp_media_attributes[type]);
params->custom_sdp_media_attributes[type] = NULL;
}
if (csa) {
params->custom_sdp_media_attributes[type] = sal_custom_sdp_attribute_clone(csa);
}
}
/*******************************************************************************
* Public functions *
******************************************************************************/
void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
}
void linphone_call_params_add_custom_sdp_attribute(LinphoneCallParams *params, const char *attribute_name, const char *attribute_value) {
params->custom_sdp_attributes = sal_custom_sdp_attribute_append(params->custom_sdp_attributes, attribute_name, attribute_value);
}
void linphone_call_params_add_custom_sdp_media_attribute(LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name, const char *attribute_value) {
params->custom_sdp_media_attributes[type] = sal_custom_sdp_attribute_append(params->custom_sdp_media_attributes[type], attribute_name, attribute_value);
}
void linphone_call_params_clear_custom_sdp_attributes(LinphoneCallParams *params) {
linphone_call_params_set_custom_sdp_attributes(params, NULL);
}
void linphone_call_params_clear_custom_sdp_media_attributes(LinphoneCallParams *params, LinphoneStreamType type) {
linphone_call_params_set_custom_sdp_media_attributes(params, type, NULL);
}
LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
return (LinphoneCallParams *)belle_sip_object_clone((const belle_sip_object_t *)cp);
}
bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
return cp->real_early_media;
}
void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled){
cp->real_early_media=enabled;
}
void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled){
cp->low_bandwidth=enabled;
}
void linphone_call_params_enable_audio(LinphoneCallParams *cp, bool_t enabled){
cp->has_audio=enabled;
if (enabled && cp->audio_dir==LinphoneMediaDirectionInactive)
cp->audio_dir=LinphoneMediaDirectionSendRecv;
}
LinphoneStatus linphone_call_params_enable_realtime_text(LinphoneCallParams *params, bool_t yesno) {
params->realtimetext_enabled=yesno;
return 0;
}
void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
cp->has_video=enabled;
if (enabled && cp->video_dir==LinphoneMediaDirectionInactive)
cp->video_dir=LinphoneMediaDirectionSendRecv;
}
const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){
return sal_custom_header_find(params->custom_headers,header_name);
}
const char * linphone_call_params_get_custom_sdp_attribute(const LinphoneCallParams *params, const char *attribute_name) {
return sal_custom_sdp_attribute_find(params->custom_sdp_attributes, attribute_name);
}
const char * linphone_call_params_get_custom_sdp_media_attribute(const LinphoneCallParams *params, LinphoneStreamType type, const char *attribute_name) {
return sal_custom_sdp_attribute_find(params->custom_sdp_media_attributes[type], attribute_name);
}
bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *cp){
return cp->in_conference;
}
LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
return cp->media_encryption;
}
LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params) {
return params->privacy;
}
float linphone_call_params_get_received_framerate(const LinphoneCallParams *cp){
return cp->received_fps;
}
MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *cp) {
return cp->recv_vsize;
}
const LinphoneVideoDefinition * linphone_call_params_get_received_video_definition(const LinphoneCallParams *cp) {
return cp->recv_vdef;
}
const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp){
return cp->record_file;
}
const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *cp) {
return sal_media_proto_to_string(get_proto_from_call_params(cp));
}
float linphone_call_params_get_sent_framerate(const LinphoneCallParams *cp){
return cp->sent_fps;
}
MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *cp) {
return cp->sent_vsize;
}
const LinphoneVideoDefinition * linphone_call_params_get_sent_video_definition(const LinphoneCallParams *cp) {
return cp->sent_vdef;
}
const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp){
return cp->session_name;
}
LinphonePayloadType *linphone_call_params_get_used_audio_payload_type(const LinphoneCallParams *cp) {
return cp->audio_codec ? linphone_payload_type_new(NULL, cp->audio_codec) : NULL;
}
LinphonePayloadType *linphone_call_params_get_used_video_payload_type(const LinphoneCallParams *cp) {
return cp->video_codec ? linphone_payload_type_new(NULL, cp->video_codec) : NULL;
}
LinphonePayloadType *linphone_call_params_get_used_text_payload_type(const LinphoneCallParams *cp) {
return cp->text_codec ? linphone_payload_type_new(NULL, cp->text_codec) : NULL;
}
const OrtpPayloadType *linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
return cp->audio_codec;
}
const OrtpPayloadType *linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
return cp->video_codec;
}
const OrtpPayloadType *linphone_call_params_get_used_text_codec(const LinphoneCallParams *cp) {
return cp->text_codec;
}
bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
return cp->low_bandwidth;
}
void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bandwidth){
cp->audio_bw=bandwidth;
}
void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e) {
cp->media_encryption = e;
}
void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) {
params->privacy=privacy;
}
void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path){
if (cp->record_file){
ms_free(cp->record_file);
cp->record_file=NULL;
}
if (path) cp->record_file=ms_strdup(path);
}
void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *name){
if (cp->session_name){
ms_free(cp->session_name);
cp->session_name=NULL;
}
if (name) cp->session_name=ms_strdup(name);
}
bool_t linphone_call_params_audio_enabled(const LinphoneCallParams *cp){
return cp->has_audio;
}
bool_t linphone_call_params_realtime_text_enabled(const LinphoneCallParams *params) {
return params->realtimetext_enabled;
}
bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
return cp->has_video;
}
LinphoneMediaDirection linphone_call_params_get_audio_direction(const LinphoneCallParams *cp) {
return cp->audio_dir;
}
LinphoneMediaDirection linphone_call_params_get_video_direction(const LinphoneCallParams *cp) {
return cp->video_dir;
}
void linphone_call_params_set_audio_direction(LinphoneCallParams *cp,LinphoneMediaDirection dir) {
cp->audio_dir=dir;
}
void linphone_call_params_set_video_direction(LinphoneCallParams *cp,LinphoneMediaDirection dir) {
cp->video_dir=dir;
}
/*******************************************************************************
* Reference and user data handling functions *
******************************************************************************/
void *linphone_call_params_get_user_data(const LinphoneCallParams *cp) {
return cp->user_data;
}
void linphone_call_params_set_user_data(LinphoneCallParams *cp, void *ud) {
cp->user_data = ud;
}
LinphoneCallParams * linphone_call_params_ref(LinphoneCallParams *cp) {
belle_sip_object_ref(cp);
return cp;
}
void linphone_call_params_unref(LinphoneCallParams *cp) {
belle_sip_object_unref(cp);
}
void linphone_call_params_enable_audio_multicast(LinphoneCallParams *params, bool_t yesno) {
params->audio_multicast_enabled=yesno;
}
bool_t linphone_call_params_audio_multicast_enabled(const LinphoneCallParams *params) {
return params->audio_multicast_enabled;
}
void linphone_call_params_enable_video_multicast(LinphoneCallParams *params, bool_t yesno) {
params->video_multicast_enabled=yesno;
}
bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *params) {
return params->video_multicast_enabled;
}
/*******************************************************************************
* Constructor and destructor functions *
******************************************************************************/
static void _linphone_call_params_uninit(LinphoneCallParams *cp){
unsigned int i;
if (cp->record_file) ms_free(cp->record_file);
if (cp->custom_headers) sal_custom_header_free(cp->custom_headers);
if (cp->custom_sdp_attributes) sal_custom_sdp_attribute_free(cp->custom_sdp_attributes);
for (i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) {
if (cp->custom_sdp_media_attributes[i]) sal_custom_sdp_attribute_free(cp->custom_sdp_media_attributes[i]);
}
if (cp->session_name) ms_free(cp->session_name);
if (cp->sent_vdef != NULL) linphone_video_definition_unref(cp->sent_vdef);
if (cp->recv_vdef != NULL) linphone_video_definition_unref(cp->recv_vdef);
}
static void _linphone_call_params_clone(LinphoneCallParams *dst, const LinphoneCallParams *src) {
unsigned int i;
/*
* Save the belle_sip_object_t part, copy the entire structure and restore the belle_sip_object_t part
*/
belle_sip_object_t tmp = dst->base;
memcpy(dst, src, sizeof(LinphoneCallParams));
dst->base = tmp;
if (src->sent_vdef) dst->sent_vdef = linphone_video_definition_ref(src->sent_vdef);
if (src->recv_vdef) dst->recv_vdef = linphone_video_definition_ref(src->recv_vdef);
if (src->record_file) dst->record_file=ms_strdup(src->record_file);
if (src->session_name) dst->session_name=ms_strdup(src->session_name);
/*
* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
*/
if (src->custom_headers) dst->custom_headers=sal_custom_header_clone(src->custom_headers);
if (src->custom_sdp_attributes) dst->custom_sdp_attributes = sal_custom_sdp_attribute_clone(src->custom_sdp_attributes);
for (i = 0; i < (unsigned int)LinphoneStreamTypeUnknown; i++) {
if (src->custom_sdp_media_attributes[i]) dst->custom_sdp_media_attributes[i] = sal_custom_sdp_attribute_clone(src->custom_sdp_media_attributes[i]);
}
}
LinphoneCallParams * linphone_call_params_new(void) {
LinphoneCallParams *cp=belle_sip_object_new(LinphoneCallParams);
cp->audio_dir=LinphoneMediaDirectionSendRecv;
cp->video_dir=LinphoneMediaDirectionSendRecv;
cp->has_audio=TRUE;
cp->realtimetext_enabled = FALSE;
return cp;
}
/* DEPRECATED */
void linphone_call_params_destroy(LinphoneCallParams *cp) {
linphone_call_params_unref(cp);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCallParams);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallParams, belle_sip_object_t,
(belle_sip_object_destroy_t)_linphone_call_params_uninit,
(belle_sip_object_clone_t)_linphone_call_params_clone, // clone
NULL, // marshal
FALSE
);

File diff suppressed because it is too large Load diff

View file

@ -67,7 +67,7 @@ static void linphone_carddav_client_to_server_sync_done(LinphoneCardDavContext *
if (!success) {
ms_error("[carddav] CardDAV client to server sync failure: %s", msg);
}
if (cdc->sync_done_cb) {
cdc->sync_done_cb(cdc, success, msg);
}
@ -80,7 +80,7 @@ static void linphone_carddav_server_to_client_sync_done(LinphoneCardDavContext *
} else {
ms_error("[carddav] CardDAV server to client sync failure: %s", msg);
}
if (cdc->sync_done_cb) {
cdc->sync_done_cb(cdc, success, msg);
}
@ -118,7 +118,7 @@ static void linphone_carddav_vcards_pulled(LinphoneCardDavContext *cdc, bctbx_li
LinphoneVcard *lvc = linphone_vcard_context_get_vcard_from_buffer(cdc->friend_list->lc->vcard_context, vCard->vcard);
LinphoneFriend *lf = NULL;
bctbx_list_t *local_friend = NULL;
if (lvc) {
// Compute downloaded vCards' URL and save it (+ eTag)
char *vCard_name = strrchr(vCard->url, '/');
@ -132,7 +132,7 @@ static void linphone_carddav_vcards_pulled(LinphoneCardDavContext *cdc, bctbx_li
linphone_vcard_unref(lvc); /*ref is now owned by friend*/
if (lf) {
local_friend = bctbx_list_find_custom(friends, (int (*)(const void*, const void*))find_matching_friend, lf);
if (local_friend) {
LinphoneFriend *lf2 = (LinphoneFriend *)local_friend->data;
lf->storage_id = lf2->storage_id;
@ -142,7 +142,7 @@ static void linphone_carddav_vcards_pulled(LinphoneCardDavContext *cdc, bctbx_li
lf->presence_received = lf2->presence_received;
lf->lc = lf2->lc;
lf->friend_list = lf2->friend_list;
if (cdc->contact_updated_cb) {
ms_debug("Contact updated: %s", linphone_friend_get_name(lf));
cdc->contact_updated_cb(cdc, lf, lf2);
@ -222,7 +222,7 @@ static void linphone_carddav_vcards_fetched(LinphoneCardDavContext *cdc, bctbx_l
bctbx_list_t *friends = cdc->friend_list->friends;
bctbx_list_t *friends_to_remove = NULL;
bctbx_list_t *temp_list = NULL;
while (friends) {
LinphoneFriend *lf = (LinphoneFriend *)friends->data;
if (lf) {
@ -258,7 +258,7 @@ static void linphone_carddav_vcards_fetched(LinphoneCardDavContext *cdc, bctbx_l
friends_to_remove = bctbx_list_next(friends_to_remove);
}
temp_list = bctbx_list_free_with_data(temp_list, (void (*)(void *))linphone_friend_unref);
linphone_carddav_pull_vcards(cdc, vCards);
bctbx_list_free_with_data(vCards, (void (*)(void *))linphone_carddav_response_free);
}
@ -338,22 +338,22 @@ static void linphone_carddav_query_free(LinphoneCardDavQuery *query) {
if (!query) {
return;
}
if (query->http_request_listener) {
belle_sip_object_unref(query->http_request_listener);
query->http_request_listener = NULL;
}
// Context will be freed later (in sync_done)
query->context = NULL;
if (query->url) {
ms_free(query->url);
}
if (query->body) {
ms_free(query->body);
}
ms_free(query);
}
@ -378,7 +378,7 @@ static bool_t is_query_client_to_server_sync(LinphoneCardDavQuery *query) {
static void process_response_from_carddav_request(void *data, const belle_http_response_event_t *event) {
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)data;
if (event->response) {
int code = belle_http_response_get_status_code(event->response);
if (code == 207 || code == 200 || code == 201 || code == 204) {
@ -469,7 +469,7 @@ static void process_auth_requested_from_carddav_request(void *data, belle_sip_au
const char *realm = belle_sip_auth_event_get_realm(event);
belle_generic_uri_t *uri = belle_generic_uri_parse(query->url);
const char *domain = belle_generic_uri_get_host(uri);
if (cdc->auth_info) {
belle_sip_auth_event_set_username(event, cdc->auth_info->username);
belle_sip_auth_event_set_passwd(event, cdc->auth_info->passwd);
@ -477,7 +477,7 @@ static void process_auth_requested_from_carddav_request(void *data, belle_sip_au
} else {
LinphoneCore *lc = cdc->friend_list->lc;
const bctbx_list_t *auth_infos = linphone_core_get_auth_info_list(lc);
ms_debug("Looking for auth info for domain %s and realm %s", domain, realm);
while (auth_infos) {
LinphoneAuthInfo *auth_info = (LinphoneAuthInfo *)auth_infos->data;
@ -492,7 +492,7 @@ static void process_auth_requested_from_carddav_request(void *data, belle_sip_au
}
auth_infos = bctbx_list_next(auth_infos);
}
if (!auth_infos) {
ms_error("[carddav] Authentication requested during CardDAV request sending, and username/password weren't provided");
if (is_query_client_to_server_sync(query)) {
@ -523,7 +523,7 @@ static void linphone_carddav_send_query(LinphoneCardDavQuery *query) {
return;
}
req = belle_http_request_create(query->method, uri, belle_sip_header_content_type_create("application", "xml; charset=utf-8"), NULL);
if (!req) {
if (cdc && cdc->sync_done_cb) {
cdc->sync_done_cb(cdc, FALSE, "Could not create belle_http_request_t");
@ -533,7 +533,7 @@ static void linphone_carddav_send_query(LinphoneCardDavQuery *query) {
linphone_carddav_query_free(query);
return;
}
ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent(cdc->friend_list->lc), linphone_core_get_version());
belle_sip_message_add_header((belle_sip_message_t *)req, belle_sip_header_create("User-Agent", ua));
ms_free(ua);
@ -544,12 +544,12 @@ static void linphone_carddav_send_query(LinphoneCardDavQuery *query) {
} else if (strcmp(query->method, "PUT")) {
belle_sip_message_add_header((belle_sip_message_t *)req, belle_sip_header_create("If-None-Match", "*"));
}
if (query->body) {
bh = belle_sip_memory_body_handler_new_copy_from_buffer(query->body, strlen(query->body), NULL, NULL);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req), bh ? BELLE_SIP_BODY_HANDLER(bh) : NULL);
}
cbs.process_response = process_response_from_carddav_request;
cbs.process_io_error = process_io_error_from_carddav_request;
cbs.process_auth_requested = process_auth_requested_from_carddav_request;
@ -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 (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);
@ -592,7 +592,7 @@ void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf)
if (!linphone_vcard_get_uid(lvc)) {
linphone_vcard_generate_unique_id(lvc);
}
if (!linphone_vcard_get_url(lvc)) {
char *url = generate_url_from_server_address_and_uid(cdc->friend_list->uri);
if (url) {
@ -607,7 +607,7 @@ void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf)
return;
}
}
query = linphone_carddav_create_put_query(cdc, lvc);
query->user_data = linphone_friend_ref(lf);
linphone_carddav_send_query(query);
@ -618,11 +618,11 @@ void linphone_carddav_put_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *lf)
} else {
msg = "Unknown error";
}
if (msg) {
ms_error("[carddav] %s", msg);
}
if (cdc && cdc->sync_done_cb) {
cdc->sync_done_cb(cdc, FALSE, msg);
}
@ -645,7 +645,7 @@ void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *
LinphoneVcard *lvc = linphone_friend_get_vcard(lf);
if (lvc && linphone_vcard_get_uid(lvc) && linphone_vcard_get_etag(lvc)) {
LinphoneCardDavQuery *query = NULL;
if (!linphone_vcard_get_url(lvc)) {
char *url = generate_url_from_server_address_and_uid(cdc->friend_list->uri);
if (url) {
@ -660,7 +660,7 @@ void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *
return;
}
}
query = linphone_carddav_create_delete_query(cdc, lvc);
linphone_carddav_send_query(query);
} else {
@ -672,11 +672,11 @@ void linphone_carddav_delete_vcard(LinphoneCardDavContext *cdc, LinphoneFriend *
} else if (!linphone_vcard_get_etag(lvc)) {
msg = "LinphoneVcard doesn't have an eTag";
}
if (msg) {
ms_error("[carddav] %s", msg);
}
if (cdc && cdc->sync_done_cb) {
cdc->sync_done_cb(cdc, FALSE, msg);
}
@ -737,7 +737,7 @@ static LinphoneCardDavQuery* linphone_carddav_create_addressbook_multiget_query(
LinphoneCardDavQuery *query = (LinphoneCardDavQuery *)ms_new0(LinphoneCardDavQuery, 1);
char *body = (char *)ms_malloc((bctbx_list_size(vcards) + 1) * 300 * sizeof(char));
bctbx_list_t *iterator = vcards;
query->context = cdc;
query->depth = "1";
query->ifmatch = NULL;
@ -758,7 +758,7 @@ static LinphoneCardDavQuery* linphone_carddav_create_addressbook_multiget_query(
strcat(body, "</card:addressbook-multiget>");
query->body = ms_strdup(body);
ms_free(body);
return query;
}

File diff suppressed because it is too large Load diff

View file

@ -1,679 +0,0 @@
/***************************************************************************
* chat_file_transfer.c
*
* Sun Jun 5 19:34:18 2005
* Copyright 2005 Simon Morlat
* Email simon dot morlat at linphone dot org
****************************************************************************/
/*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphone/core.h"
#include "private.h"
#include "ortp/b64.h"
static bool_t file_transfer_in_progress_and_valid(LinphoneChatMessage* msg) {
return (msg->chat_room && msg->chat_room->lc && msg->http_request && !belle_http_request_is_cancelled(msg->http_request));
}
static void _release_http_request(LinphoneChatMessage* msg) {
if (msg->http_request) {
belle_sip_object_unref(msg->http_request);
msg->http_request = NULL;
if (msg->http_listener){
belle_sip_object_unref(msg->http_listener);
msg->http_listener = NULL;
// unhold the reference that the listener was holding on the message
linphone_chat_message_unref(msg);
}
}
}
static void linphone_chat_message_process_io_error_upload(void *data, const belle_sip_io_error_event_t *event) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
ms_error("I/O Error during file upload of msg [%p]", msg);
linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered);
_release_http_request(msg);
linphone_chat_room_remove_transient_message(msg->chat_room, msg);
linphone_chat_message_unref(msg);
}
static void linphone_chat_message_process_auth_requested_upload(void *data, belle_sip_auth_event_t *event) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
ms_error("Error during file upload: auth requested for msg [%p]", msg);
linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered);
_release_http_request(msg);
linphone_chat_room_remove_transient_message(msg->chat_room, msg);
linphone_chat_message_unref(msg);
}
static void linphone_chat_message_process_io_error_download(void *data, const belle_sip_io_error_event_t *event) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
ms_error("I/O Error during file download msg [%p]", msg);
linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError);
_release_http_request(msg);
}
static void linphone_chat_message_process_auth_requested_download(void *data, belle_sip_auth_event_t *event) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
ms_error("Error during file download : auth requested for msg [%p]", msg);
linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError);
_release_http_request(msg);
}
static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *m,
void *data, size_t offset, size_t total) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
if (!file_transfer_in_progress_and_valid(msg)) {
ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__);
_release_http_request(msg);
return;
}
if (linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->callbacks)) {
linphone_chat_message_cbs_get_file_transfer_progress_indication(msg->callbacks)(
msg, msg->file_transfer_information, offset, total);
} else {
/* Legacy: call back given by application level */
linphone_core_notify_file_transfer_progress_indication(msg->chat_room->lc, msg, msg->file_transfer_information,
offset, total);
}
}
static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m,
void *data, size_t offset, uint8_t *buffer, size_t *size) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
LinphoneCore *lc = NULL;
LinphoneImEncryptionEngine *imee = NULL;
int retval = -1;
if (!file_transfer_in_progress_and_valid(msg)) {
if (msg->http_request) {
ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__);
_release_http_request(msg);
}
return BELLE_SIP_STOP;
}
lc = msg->chat_room->lc;
/* if we've not reach the end of file yet, ask for more data */
/* in case of file body handler, won't be called */
if (msg->file_transfer_filepath == NULL && offset < linphone_content_get_size(msg->file_transfer_information)) {
/* get data from call back */
LinphoneChatMessageCbsFileTransferSendCb file_transfer_send_cb = linphone_chat_message_cbs_get_file_transfer_send(msg->callbacks);
if (file_transfer_send_cb) {
LinphoneBuffer *lb = file_transfer_send_cb(msg, msg->file_transfer_information, offset, *size);
if (lb == NULL) {
*size = 0;
} else {
*size = linphone_buffer_get_size(lb);
memcpy(buffer, linphone_buffer_get_content(lb), *size);
linphone_buffer_unref(lb);
}
} else {
/* Legacy */
linphone_core_notify_file_transfer_send(lc, msg, msg->file_transfer_information, (char *)buffer, size);
}
}
imee = linphone_core_get_im_encryption_engine(lc);
if (imee) {
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs);
if (cb_process_uploading_file) {
size_t max_size = *size;
uint8_t *encrypted_buffer = (uint8_t *)ms_malloc0(max_size);
retval = cb_process_uploading_file(imee, msg, offset, (const uint8_t *)buffer, size, encrypted_buffer);
if (retval == 0) {
if (*size > max_size) {
ms_error("IM encryption engine process upload file callback returned a size bigger than the size of the buffer, so it will be truncated !");
*size = max_size;
}
memcpy(buffer, encrypted_buffer, *size);
}
ms_free(encrypted_buffer);
}
}
return retval <= 0 ? BELLE_SIP_CONTINUE : BELLE_SIP_STOP;
}
static void on_send_end(belle_sip_user_body_handler_t *bh, void *data) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
LinphoneCore *lc = msg->chat_room->lc;
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc);
if (imee) {
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
LinphoneImEncryptionEngineCbsUploadingFileCb cb_process_uploading_file = linphone_im_encryption_engine_cbs_get_process_uploading_file(imee_cbs);
if (cb_process_uploading_file) {
cb_process_uploading_file(imee, msg, 0, NULL, NULL, NULL);
}
}
}
static void file_upload_end_background_task(LinphoneChatMessage *obj){
if (obj->bg_task_id){
ms_message("channel [%p]: ending file upload background task with id=[%lx].",obj,obj->bg_task_id);
sal_end_background_task(obj->bg_task_id);
obj->bg_task_id=0;
}
}
static void file_upload_background_task_ended(LinphoneChatMessage *obj){
ms_warning("channel [%p]: file upload background task has to be ended now, but work isn't finished.",obj);
file_upload_end_background_task(obj);
}
static void file_upload_begin_background_task(LinphoneChatMessage *obj){
if (obj->bg_task_id==0){
obj->bg_task_id=sal_begin_background_task("file transfer upload",(void (*)(void*))file_upload_background_task_ended, obj);
if (obj->bg_task_id) ms_message("channel [%p]: starting file upload background task with id=[%lx].",obj,obj->bg_task_id);
}
}
static void linphone_chat_message_process_response_from_post_file(void *data,
const belle_http_response_event_t *event) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
if (msg->http_request && !file_transfer_in_progress_and_valid(msg)) {
ms_warning("Cancelled request for %s msg [%p], ignoring %s", msg->chat_room?"":"ORPHAN", msg, __FUNCTION__);
_release_http_request(msg);
return;
}
/* check the answer code */
if (event->response) {
int code = belle_http_response_get_status_code(event->response);
if (code == 204) { /* this is the reply to the first post to the server - an empty msg */
/* start uploading the file */
belle_sip_multipart_body_handler_t *bh;
char *first_part_header;
belle_sip_body_handler_t *first_part_bh;
bool_t is_file_encryption_enabled = FALSE;
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(msg->chat_room->lc);
if (imee) {
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, msg->chat_room);
}
}
/* shall we encrypt the file */
if (is_file_encryption_enabled) {
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, msg->chat_room, msg);
}
/* 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 = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"filename.txt\"");
} else {
/* temporary storage for the Content-disposition header value */
first_part_header = belle_sip_strdup_printf("form-data; name=\"File\"; filename=\"%s\"",
linphone_content_get_name(msg->file_transfer_information));
}
/* create a user body handler to take care of the file and add the content disposition and content-type
* headers */
first_part_bh = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(
linphone_content_get_size(msg->file_transfer_information),
linphone_chat_message_file_transfer_on_progress, NULL, NULL,
on_send_body, on_send_end, msg);
if (msg->file_transfer_filepath != NULL) {
belle_sip_user_body_handler_t *body_handler = (belle_sip_user_body_handler_t *)first_part_bh;
first_part_bh = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(msg->file_transfer_filepath,
NULL, msg); // No need to add again the callback for progression, otherwise it will be called twice
linphone_content_set_size(msg->file_transfer_information, belle_sip_file_body_handler_get_file_size((belle_sip_file_body_handler_t *)first_part_bh));
belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)first_part_bh, body_handler);
} else if (linphone_content_get_buffer(msg->file_transfer_information) != NULL) {
first_part_bh = (belle_sip_body_handler_t *)belle_sip_memory_body_handler_new_from_buffer(
linphone_content_get_buffer(msg->file_transfer_information),
linphone_content_get_size(msg->file_transfer_information), linphone_chat_message_file_transfer_on_progress, msg);
}
belle_sip_body_handler_add_header(first_part_bh,
belle_sip_header_create("Content-disposition", first_part_header));
belle_sip_free(first_part_header);
belle_sip_body_handler_add_header(first_part_bh,
(belle_sip_header_t *)belle_sip_header_content_type_create(
linphone_content_get_type(msg->file_transfer_information),
linphone_content_get_subtype(msg->file_transfer_information)));
/* insert it in a multipart body handler which will manage the boundaries of multipart msg */
bh = belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, first_part_bh, NULL);
linphone_chat_message_ref(msg);
_release_http_request(msg);
file_upload_begin_background_task(msg);
linphone_chat_room_upload_file(msg);
belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(msg->http_request), BELLE_SIP_BODY_HANDLER(bh));
linphone_chat_message_unref(msg);
} else if (code == 200) { /* file has been uploaded correctly, get server reply and send it */
const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response);
if (body && strlen(body) > 0) {
/* 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 = linphone_content_get_key(msg->file_transfer_information);
size_t content_key_size = linphone_content_get_key_size(msg->file_transfer_information);
if (content_key != NULL) {
/* parse the msg body */
xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)body);
xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody);
if (cur != NULL) {
cur = cur->xmlChildrenNode;
while (cur != NULL) {
if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check
it has a type="file" attribute */
xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type");
if (!xmlStrcmp(typeAttribute,
(const xmlChar *)"file")) { /* this is the node we are looking for : add a
file-key children node */
xmlNodePtr fileInfoNodeChildren =
cur
->xmlChildrenNode; /* need to parse the children node to update the file-name
one */
/* convert key to base64 */
size_t b64Size = b64::b64_encode(NULL, content_key_size, NULL, 0);
char *keyb64 = (char *)ms_malloc0(b64Size + 1);
int xmlStringLength;
b64Size = b64::b64_encode(content_key, content_key_size, keyb64, b64Size);
keyb64[b64Size] = '\0'; /* libxml need a null terminated string */
/* add the node containing the key to the file-info node */
xmlNewTextChild(cur, NULL, (const xmlChar *)"file-key", (const xmlChar *)keyb64);
xmlFree(typeAttribute);
ms_free(keyb64);
/* look for the file-name node and update its content */
while (fileInfoNodeChildren != NULL) {
if (!xmlStrcmp(
fileInfoNodeChildren->name,
(const xmlChar *)"file-name")) { /* we found a the file-name node, update
its content with the real filename */
/* update node content */
xmlNodeSetContent(fileInfoNodeChildren,
(const xmlChar *)(linphone_content_get_name(
msg->file_transfer_information)));
break;
}
fileInfoNodeChildren = fileInfoNodeChildren->next;
}
/* dump the xml into msg->message */
xmlDocDumpFormatMemoryEnc(xmlMessageBody, (xmlChar **)&msg->message, &xmlStringLength,
"UTF-8", 0);
break;
}
xmlFree(typeAttribute);
}
cur = cur->next;
}
}
xmlFreeDoc(xmlMessageBody);
} else { /* no encryption key, transfer in plain, just copy the msg sent by server */
msg->message = ms_strdup(body);
}
linphone_chat_message_set_content_type(msg, "application/vnd.gsma.rcs-ft-http+xml");
linphone_chat_message_ref(msg);
linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone);
_release_http_request(msg);
_linphone_chat_room_send_message(msg->chat_room, msg);
file_upload_end_background_task(msg);
linphone_chat_message_unref(msg);
} else {
ms_warning("Received empty response from server, file transfer failed");
linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered);
_release_http_request(msg);
file_upload_end_background_task(msg);
linphone_chat_message_unref(msg);
}
} else if (code == 400) {
ms_warning("Received HTTP code response %d for file transfer, probably meaning file is too large", code);
linphone_chat_message_update_state(msg, LinphoneChatMessageStateFileTransferError);
_release_http_request(msg);
file_upload_end_background_task(msg);
linphone_chat_message_unref(msg);
} else {
ms_warning("Unhandled HTTP code response %d for file transfer", code);
linphone_chat_message_update_state(msg, LinphoneChatMessageStateNotDelivered);
_release_http_request(msg);
file_upload_end_background_task(msg);
linphone_chat_message_unref(msg);
}
}
}
const LinphoneContent *linphone_chat_message_get_file_transfer_information(const LinphoneChatMessage *msg) {
return msg->file_transfer_information;
}
static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *m, void *data, size_t offset, uint8_t *buffer, size_t size) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
LinphoneCore *lc = NULL;
LinphoneImEncryptionEngine *imee = NULL;
int retval = -1;
uint8_t *decrypted_buffer = NULL;
if (!msg->chat_room) {
linphone_chat_message_cancel_file_transfer(msg);
return;
}
lc = msg->chat_room->lc;
if (lc == NULL){
return; /*might happen during linphone_core_destroy()*/
}
if (!msg->http_request || belle_http_request_is_cancelled(msg->http_request)) {
ms_warning("Cancelled request for msg [%p], ignoring %s", msg, __FUNCTION__);
return;
}
/* first call may be with a zero size, ignore it */
if (size == 0) {
return;
}
decrypted_buffer = (uint8_t *)ms_malloc0(size);
imee = linphone_core_get_im_encryption_engine(lc);
if (imee) {
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs);
if (cb_process_downloading_file) {
retval = cb_process_downloading_file(imee, msg, offset, (const uint8_t *)buffer, size, decrypted_buffer);
if (retval == 0) {
memcpy(buffer, decrypted_buffer, size);
}
}
}
ms_free(decrypted_buffer);
if (retval <= 0) {
if (msg->file_transfer_filepath == NULL) {
if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) {
LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size);
linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)(msg, msg->file_transfer_information, lb);
linphone_buffer_unref(lb);
} else {
/* Legacy: call back given by application level */
linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, (const char *)buffer, size);
}
}
} else {
ms_warning("File transfer decrypt failed with code %d", (int)retval);
linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError);
}
return;
}
static void on_recv_end(belle_sip_user_body_handler_t *bh, void *data) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
LinphoneCore *lc = msg->chat_room->lc;
LinphoneImEncryptionEngine *imee = linphone_core_get_im_encryption_engine(lc);
int retval = -1;
if (imee) {
LinphoneImEncryptionEngineCbs *imee_cbs = linphone_im_encryption_engine_get_callbacks(imee);
LinphoneImEncryptionEngineCbsDownloadingFileCb cb_process_downloading_file = linphone_im_encryption_engine_cbs_get_process_downloading_file(imee_cbs);
if (cb_process_downloading_file) {
retval = cb_process_downloading_file(imee, msg, 0, NULL, 0, NULL);
}
}
if (retval <= 0) {
if (msg->file_transfer_filepath == NULL) {
if (linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)) {
LinphoneBuffer *lb = linphone_buffer_new();
linphone_chat_message_cbs_get_file_transfer_recv(msg->callbacks)(msg, msg->file_transfer_information, lb);
linphone_buffer_unref(lb);
} else {
/* Legacy: call back given by application level */
linphone_core_notify_file_transfer_recv(lc, msg, msg->file_transfer_information, NULL, 0);
}
}
}
if (retval <= 0 && linphone_chat_message_get_state(msg) != LinphoneChatMessageStateFileTransferError) {
linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferDone);
}
}
static LinphoneContent *linphone_chat_create_file_transfer_information_from_headers(const belle_sip_message_t *m) {
LinphoneContent *content = linphone_content_new();
belle_sip_header_content_length_t *content_length_hdr =
BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(m, "Content-Length"));
belle_sip_header_content_type_t *content_type_hdr =
BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_message_get_header(m, "Content-Type"));
const char *type = NULL, *subtype = NULL;
linphone_content_set_name(content, "");
if (content_type_hdr) {
type = belle_sip_header_content_type_get_type(content_type_hdr);
subtype = belle_sip_header_content_type_get_subtype(content_type_hdr);
ms_message("Extracted content type %s / %s from header", type ? type : "", subtype ? subtype : "");
if (type)
linphone_content_set_type(content, type);
if (subtype)
linphone_content_set_subtype(content, subtype);
}
if (content_length_hdr) {
linphone_content_set_size(content, belle_sip_header_content_length_get_content_length(content_length_hdr));
ms_message("Extracted content length %i from header", (int)linphone_content_get_size(content));
}
return content;
}
static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
if (event->response) {
/*we are receiving a response, set a specific body handler to acquire the response.
* if not done, belle-sip will create a memory body handler, the default*/
belle_sip_message_t *response = BELLE_SIP_MESSAGE(event->response);
belle_sip_body_handler_t *body_handler = NULL;
size_t body_size = 0;
if (msg->file_transfer_information == NULL) {
ms_warning("No file transfer information for msg %p: creating...", msg);
msg->file_transfer_information = linphone_chat_create_file_transfer_information_from_headers(response);
}
if (msg->file_transfer_information) {
body_size = linphone_content_get_size(msg->file_transfer_information);
}
body_handler = (belle_sip_body_handler_t *)belle_sip_user_body_handler_new(body_size, linphone_chat_message_file_transfer_on_progress, NULL, on_recv_body, NULL, on_recv_end, msg);
if (msg->file_transfer_filepath != NULL) {
belle_sip_user_body_handler_t *bh = (belle_sip_user_body_handler_t *)body_handler;
body_handler = (belle_sip_body_handler_t *)belle_sip_file_body_handler_new(
msg->file_transfer_filepath, linphone_chat_message_file_transfer_on_progress, msg);
if (belle_sip_body_handler_get_size((belle_sip_body_handler_t *)body_handler) == 0) {
/* If the size of the body has not been initialized from the file stat, use the one from the
* file_transfer_information. */
belle_sip_body_handler_set_size((belle_sip_body_handler_t *)body_handler, body_size);
}
belle_sip_file_body_handler_set_user_body_handler((belle_sip_file_body_handler_t *)body_handler, bh);
}
belle_sip_message_set_body_handler((belle_sip_message_t *)event->response, body_handler);
}
}
static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event) {
LinphoneChatMessage *msg = (LinphoneChatMessage *)data;
/* check the answer code */
if (event->response) {
int code = belle_http_response_get_status_code(event->response);
if (code >= 400 && code < 500) {
ms_warning("File transfer failed with code %d", code);
linphone_chat_message_set_state(msg, LinphoneChatMessageStateFileTransferError);
} else if (code != 200) {
ms_warning("Unhandled HTTP code response %d for file transfer", code);
}
_release_http_request(msg);
}
}
int _linphone_chat_room_start_http_transfer(LinphoneChatMessage *msg, const char* url, const char* action, const belle_http_request_listener_callbacks_t *cbs) {
belle_generic_uri_t *uri = NULL;
const char* ua = linphone_core_get_user_agent(msg->chat_room->lc);
if (url == NULL) {
ms_warning("Cannot process file transfer msg: no file remote URI configured.");
goto error;
}
uri = belle_generic_uri_parse(url);
if (uri == NULL || belle_generic_uri_get_host(uri)==NULL) {
ms_warning("Cannot process file transfer msg: incorrect file remote URI configured '%s'.", url);
goto error;
}
msg->http_request = belle_http_request_create(action, uri, belle_sip_header_create("User-Agent", ua), NULL);
if (msg->http_request == NULL) {
ms_warning("Could not create http request for uri %s", url);
goto error;
}
/* keep a reference to the http request to be able to cancel it during upload */
belle_sip_object_ref(msg->http_request);
/* give msg to listener to be able to start the actual file upload when server answer a 204 No content */
msg->http_listener = belle_http_request_listener_create_from_callbacks(cbs, linphone_chat_message_ref(msg));
belle_http_provider_send_request(msg->chat_room->lc->http_provider, msg->http_request, msg->http_listener);
return 0;
error:
if (uri) {
belle_sip_object_unref(uri);
}
return -1;
}
int linphone_chat_room_upload_file(LinphoneChatMessage *msg) {
belle_http_request_listener_callbacks_t cbs = {0};
int err;
if (msg->http_request){
ms_error("linphone_chat_room_upload_file(): there is already an upload in progress.");
return -1;
}
cbs.process_response = linphone_chat_message_process_response_from_post_file;
cbs.process_io_error = linphone_chat_message_process_io_error_upload;
cbs.process_auth_requested = linphone_chat_message_process_auth_requested_upload;
err = _linphone_chat_room_start_http_transfer(msg, linphone_core_get_file_transfer_server(msg->chat_room->lc), "POST", &cbs);
if (err == -1){
linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered);
}
return err;
}
LinphoneStatus linphone_chat_message_download_file(LinphoneChatMessage *msg) {
belle_http_request_listener_callbacks_t cbs = {0};
int err;
if (msg->http_request){
ms_error("linphone_chat_message_download_file(): there is already a download in progress");
return -1;
}
cbs.process_response_headers = linphone_chat_process_response_headers_from_get_file;
cbs.process_response = linphone_chat_process_response_from_get_file;
cbs.process_io_error = linphone_chat_message_process_io_error_download;
cbs.process_auth_requested = linphone_chat_message_process_auth_requested_download;
err = _linphone_chat_room_start_http_transfer(msg, msg->external_body_url, "GET", &cbs);
if (err == -1) return -1;
/* start the download, status is In Progress */
linphone_chat_message_set_state(msg, LinphoneChatMessageStateInProgress);
return 0;
}
void linphone_chat_message_start_file_download(LinphoneChatMessage *msg,
LinphoneChatMessageStateChangedCb status_cb, void *ud) {
msg->message_state_changed_cb = status_cb;
msg->message_state_changed_user_data = ud;
linphone_chat_message_download_file(msg);
}
void _linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg, bool_t unref) {
if (msg->http_request) {
if (msg->state == LinphoneChatMessageStateInProgress) {
linphone_chat_message_set_state(msg, LinphoneChatMessageStateNotDelivered);
}
if (!belle_http_request_is_cancelled(msg->http_request)) {
if (msg->chat_room) {
ms_message("Canceling file transfer %s - msg [%p] chat room[%p]"
, (msg->external_body_url == NULL) ? linphone_core_get_file_transfer_server(msg->chat_room->lc) : msg->external_body_url
, msg
, msg->chat_room);
belle_http_provider_cancel_request(msg->chat_room->lc->http_provider, msg->http_request);
if ((msg->dir == LinphoneChatMessageOutgoing) && unref) {
// must release it
linphone_chat_message_unref(msg);
}
} else {
ms_message("Warning: http request still running for ORPHAN msg [%p]: this is a memory leak", msg);
}
}
_release_http_request(msg);
} else {
ms_message("No existing file transfer - nothing to cancel");
}
}
void linphone_chat_message_cancel_file_transfer(LinphoneChatMessage *msg) {
_linphone_chat_message_cancel_file_transfer(msg, TRUE);
}
void linphone_chat_message_set_file_transfer_filepath(LinphoneChatMessage *msg, const char *filepath) {
if (msg->file_transfer_filepath != NULL) {
ms_free(msg->file_transfer_filepath);
}
msg->file_transfer_filepath = ms_strdup(filepath);
}
const char *linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg) {
return msg->file_transfer_filepath;
}
LinphoneChatMessage *linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr,
const LinphoneContent *initial_content) {
LinphoneChatMessage *msg = belle_sip_object_new(LinphoneChatMessage);
msg->callbacks = linphone_chat_message_cbs_new();
msg->chat_room = (LinphoneChatRoom *)cr;
msg->message = NULL;
msg->file_transfer_information = linphone_content_copy(initial_content);
msg->dir = LinphoneChatMessageOutgoing;
linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr));
msg->from = linphone_address_new(linphone_core_get_identity(cr->lc)); /*direct assignment*/
/* this will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */
msg->content_type = NULL;
/* this will store the http request during file upload to the server */
msg->http_request = NULL;
msg->time = ms_time(0);
return msg;
}

File diff suppressed because it is too large Load diff

View file

@ -17,9 +17,10 @@
#ifndef CONTACT_PROVIDERS_PRIV_H
#define CONTACT_PROVIDERS_PRIV_H
#include "private.h"
#include "linphone/core.h"
#include "c-wrapper/c-wrapper.h"
/* Base for contact search and contact provider */
struct _LinphoneContactSearch{

View file

@ -14,9 +14,10 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "contact_providers_priv.h"
#include "linphone/contactprovider.h"
#include <linphone/core.h>
#include "linphone/core.h"
#include "contact_providers_priv.h"
/* ############################ *
* LinphoneContactSearchRequest *

View file

@ -1,241 +0,0 @@
/*
linphone
Copyright (C) 2010-2014 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/core.h"
#include "private.h"
static void linphone_content_set_sal_body_handler(LinphoneContent *content, SalBodyHandler *body_handler) {
if (content->body_handler != NULL) {
sal_body_handler_unref(content->body_handler);
content->body_handler = NULL;
}
content->body_handler = sal_body_handler_ref(body_handler);
}
static LinphoneContent * linphone_content_new_with_body_handler(SalBodyHandler *body_handler) {
LinphoneContent *content = belle_sip_object_new(LinphoneContent);
belle_sip_object_ref(content);
content->owned_fields = TRUE;
content->cryptoContext = NULL; /* this field is managed externally by encryption/decryption functions so be careful to initialise it to NULL */
if (body_handler == NULL) {
linphone_content_set_sal_body_handler(content, sal_body_handler_new());
} else {
linphone_content_set_sal_body_handler(content, body_handler);
}
return content;
}
static void linphone_content_destroy(LinphoneContent *content) {
if (content->owned_fields == TRUE) {
if (content->body_handler) sal_body_handler_unref(content->body_handler);
if (content->name) belle_sip_free(content->name);
if (content->key) belle_sip_free(content->key);
/* note : crypto context is allocated/destroyed by the encryption function */
}
}
static void linphone_content_clone(LinphoneContent *obj, const LinphoneContent *ref) {
obj->owned_fields = TRUE;
linphone_content_set_sal_body_handler(obj, sal_body_handler_new());
if ((linphone_content_get_type(ref) != NULL) || (linphone_content_get_subtype(ref) != NULL)) {
linphone_content_set_type(obj, linphone_content_get_type(ref));
linphone_content_set_subtype(obj, linphone_content_get_subtype(ref));
}
if (linphone_content_get_encoding(ref) != NULL) {
linphone_content_set_encoding(obj, linphone_content_get_encoding(ref));
}
linphone_content_set_name(obj, linphone_content_get_name(ref));
linphone_content_set_key(obj, linphone_content_get_key(ref), linphone_content_get_key_size(ref));
if (linphone_content_get_buffer(ref) != NULL) {
linphone_content_set_buffer(obj, linphone_content_get_buffer(ref), linphone_content_get_size(ref));
} else {
linphone_content_set_size(obj, linphone_content_get_size(ref));
}
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContent);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneContent, belle_sip_object_t,
(belle_sip_object_destroy_t)linphone_content_destroy,
(belle_sip_object_clone_t)linphone_content_clone,
NULL, // marshal
TRUE
);
LinphoneContent * linphone_core_create_content(LinphoneCore *lc) {
return linphone_content_new();
}
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_get_user_data(const LinphoneContent *content) {
return content->user_data;
}
void linphone_content_set_user_data(LinphoneContent *content, void *ud) {
content->user_data = ud;
}
const char * linphone_content_get_type(const LinphoneContent *content) {
return sal_body_handler_get_type(content->body_handler);
}
void linphone_content_set_type(LinphoneContent *content, const char *type) {
sal_body_handler_set_type(content->body_handler, type);
}
const char * linphone_content_get_subtype(const LinphoneContent *content) {
return sal_body_handler_get_subtype(content->body_handler);
}
void linphone_content_set_subtype(LinphoneContent *content, const char *subtype) {
sal_body_handler_set_subtype(content->body_handler, subtype);
}
void * linphone_content_get_buffer(const LinphoneContent *content) {
return sal_body_handler_get_data(content->body_handler);
}
void linphone_content_set_buffer(LinphoneContent *content, const void *buffer, size_t size) {
void *data;
sal_body_handler_set_size(content->body_handler, size);
data = belle_sip_malloc(size + 1);
memcpy(data, buffer, size);
((char *)data)[size] = '\0';
sal_body_handler_set_data(content->body_handler, data);
}
const char * linphone_content_get_string_buffer(const LinphoneContent *content) {
return (const char *)linphone_content_get_buffer(content);
}
void linphone_content_set_string_buffer(LinphoneContent *content, const char *buffer) {
sal_body_handler_set_size(content->body_handler, strlen(buffer));
sal_body_handler_set_data(content->body_handler, belle_sip_strdup(buffer));
}
size_t linphone_content_get_size(const LinphoneContent *content) {
return sal_body_handler_get_size(content->body_handler);
}
void linphone_content_set_size(LinphoneContent *content, size_t size) {
sal_body_handler_set_size(content->body_handler, size);
}
const char * linphone_content_get_encoding(const LinphoneContent *content) {
return sal_body_handler_get_encoding(content->body_handler);
}
void linphone_content_set_encoding(LinphoneContent *content, const char *encoding) {
sal_body_handler_set_encoding(content->body_handler, encoding);
}
const char * linphone_content_get_name(const LinphoneContent *content) {
return content->name;
}
void linphone_content_set_name(LinphoneContent *content, const char *name) {
if (content->name != NULL) {
belle_sip_free(content->name);
content->name = NULL;
}
if (name != NULL) {
content->name = belle_sip_strdup(name);
}
}
size_t linphone_content_get_key_size(const LinphoneContent *content) {
return content->keyLength;
}
const char * linphone_content_get_key(const LinphoneContent *content) {
return content->key;
}
void linphone_content_set_key(LinphoneContent *content, const char *key, const size_t keyLength) {
if (content->key != NULL) {
belle_sip_free(content->key);
content->key = NULL;
}
if (key != NULL) {
content->key = reinterpret_cast<char *>(belle_sip_malloc(keyLength + 1));
memcpy(content->key, key, keyLength);
content->key[keyLength] = '\0';
content->keyLength = keyLength;
}
}
/* 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);
}
bool_t linphone_content_is_multipart(const LinphoneContent *content) {
return sal_body_handler_is_multipart(content->body_handler);
}
LinphoneContent * linphone_content_get_part(const LinphoneContent *content, int idx) {
SalBodyHandler *part_body_handler;
if (!linphone_content_is_multipart(content)) return NULL;
part_body_handler = sal_body_handler_get_part(content->body_handler, idx);
return linphone_content_from_sal_body_handler(part_body_handler);
}
LinphoneContent * linphone_content_find_part_by_header(const LinphoneContent *content, const char *header_name, const char *header_value) {
SalBodyHandler *part_body_handler;
if (!linphone_content_is_multipart(content)) return NULL;
part_body_handler = sal_body_handler_find_part_by_header(content->body_handler, header_name, header_value);
return linphone_content_from_sal_body_handler(part_body_handler);
}
const char * linphone_content_get_custom_header(const LinphoneContent *content, const char *header_name) {
return sal_body_handler_get_header(content->body_handler, header_name);
}
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_ref(belle_sip_object_clone(BELLE_SIP_OBJECT(ref)));
}
LinphoneContent * linphone_content_from_sal_body_handler(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) {
if (content == NULL) return NULL;
return content->body_handler;
}

35
coreapi/core_private.h Normal file
View file

@ -0,0 +1,35 @@
/*
* core_private.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 _CORE_PRIVATE_H_
#define _CORE_PRIVATE_H_
#include "linphone/types.h"
#include "private_structs.h"
#include "private_types.h"
struct _LinphoneCore {
belle_sip_object_t base;
std::shared_ptr<LinphonePrivate::Core> cppPtr;
std::weak_ptr<LinphonePrivate::Core> weakCppPtr;
int owner;
LINPHONE_CORE_STRUCT_FIELDS
};
#endif /* _CORE_PRIVATE_H_ */

View file

@ -19,314 +19,3 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
*/
#include "linphone/core_utils.h"
/*
* http://en.wikipedia.org/wiki/Telephone_numbering_plan
* http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe
* imported from https://en.wikipedia.org/wiki/List_of_mobile_phone_number_series_by_country
*/
static LinphoneDialPlan const dial_plans[]={
//Country , iso country code, e164 country calling code, number length, international usual prefix
{"Afghanistan" ,"AF" , "93" , 9 , "00" },
{"Albania" ,"AL" , "355" , 9 , "00" },
{"Algeria" ,"DZ" , "213" , 9 , "00" },
{"American Samoa" ,"AS" , "1" , 10 , "011" },
{"Andorra" ,"AD" , "376" , 6 , "00" },
{"Angola" ,"AO" , "244" , 9 , "00" },
{"Anguilla" ,"AI" , "1" , 10 , "011" },
{"Antigua and Barbuda" ,"AG" , "1" , 10 , "011" },
{"Argentina" ,"AR" , "54" , 10 , "00" },
{"Armenia" ,"AM" , "374" , 8 , "00" },
{"Aruba" ,"AW" , "297" , 7 , "011" },
{"Australia" ,"AU" , "61" , 9 , "0011"},
{"Austria" ,"AT" , "43" , 11 , "00" }, /*11 digits are possible, most numbers have 10 digits*/
{"Azerbaijan" ,"AZ" , "994" , 9 , "00" },
{"Bahamas" ,"BS" , "1" , 10 , "011" },
{"Bahrain" ,"BH" , "973" , 8 , "00" },
{"Bangladesh" ,"BD" , "880" , 10 , "00" },
{"Barbados" ,"BB" , "1" , 10 , "011" },
{"Belarus" ,"BY" , "375" , 9 , "00" },
{"Belgium" ,"BE" , "32" , 9 , "00" },
{"Belize" ,"BZ" , "501" , 7 , "00" },
{"Benin" ,"BJ" , "229" , 8 , "00" },
{"Bermuda" ,"BM" , "1" , 10 , "011" },
{"Bhutan" ,"BT" , "975" , 8 , "00" },
{"Bolivia" ,"BO" , "591" , 8 , "00" },
{"Bosnia and Herzegovina" ,"BA" , "387" , 8 , "00" },
{"Botswana" ,"BW" , "267" , 8 , "00" },
{"Brazil" ,"BR" , "55" , 11 , "00" },
{"Brunei Darussalam" ,"BN" , "673" , 7 , "00" },
{"Bulgaria" ,"BG" , "359" , 9 , "00" },
{"Burkina Faso" ,"BF" , "226" , 8 , "00" },
{"Burundi" ,"BI" , "257" , 8 , "011" },
{"Cambodia" ,"KH" , "855" , 9 , "00" },
{"Cameroon" ,"CM" , "237" , 9 , "00" },
{"Canada" ,"CA" , "1" , 10 , "011" },
{"Cape Verde" ,"CV" , "238" , 7 , "00" },
{"Cayman Islands" ,"KY" , "1" , 10 , "011" },
{"Central African Republic" ,"CF" , "236" , 8 , "00" },
{"Chad" ,"TD" , "235" , 8 , "00" },
{"Chile" ,"CL" , "56" , 9 , "00" },
{"China" ,"CN" , "86" , 11 , "00" },
{"Colombia" ,"CO" , "57" , 10 , "00" },
{"Comoros" ,"KM" , "269" , 7 , "00" },
{"Congo" ,"CG" , "242" , 9 , "00" },
{"Congo Democratic Republic" ,"CD" , "243" , 9 , "00" },
{"Cook Islands" ,"CK" , "682" , 5 , "00" },
{"Costa Rica" ,"CR" , "506" , 8 , "00" },
{"Cote d'Ivoire" ,"AD" , "225" , 8 , "00" },
{"Croatia" ,"HR" , "385" , 9 , "00" },
{"Cuba" ,"CU" , "53" , 8 , "119" },
{"Cyprus" ,"CY" , "357" , 8 , "00" },
{"Czech Republic" ,"CZ" , "420" , 9 , "00" },
{"Denmark" ,"DK" , "45" , 8 , "00" },
{"Djibouti" ,"DJ" , "253" , 8 , "00" },
{"Dominica" ,"DM" , "1" , 10 , "011" },
{"Dominican Republic" ,"DO" , "1" , 10 , "011" },
{"Ecuador" ,"EC" , "593" , 9 , "00" },
{"Egypt" ,"EG" , "20" , 10 , "00" },
{"El Salvador" ,"SV" , "503" , 8 , "00" },
{"Equatorial Guinea" ,"GQ" , "240" , 9 , "00" },
{"Eritrea" ,"ER" , "291" , 7 , "00" },
{"Estonia" ,"EE" , "372" , 8 , "00" },
{"Ethiopia" ,"ET" , "251" , 9 , "00" },
{"Falkland Islands" ,"FK" , "500" , 5 , "00" },
{"Faroe Islands" ,"FO" , "298" , 6 , "00" },
{"Fiji" ,"FJ" , "679" , 7 , "00" },
{"Finland" ,"FI" , "358" , 9 , "00" },
{"France" ,"FR" , "33" , 9 , "00" },
{"French Guiana" ,"GF" , "594" , 9 , "00" },
{"French Polynesia" ,"PF" , "689" , 6 , "00" },
{"Gabon" ,"GA" , "241" , 8 , "00" },
{"Gambia" ,"GM" , "220" , 7 , "00" },
{"Georgia" ,"GE" , "995" , 9 , "00" },
{"Germany" ,"DE" , "49" , 11 , "00" },
{"Ghana" ,"GH" , "233" , 9 , "00" },
{"Gibraltar" ,"GI" , "350" , 8 , "00" },
{"Greece" ,"GR" , "30" ,10 , "00" },
{"Greenland" ,"GL" , "299" , 6 , "00" },
{"Grenada" ,"GD" , "1" , 10 , "011" },
{"Guadeloupe" ,"GP" , "590" , 9 , "00" },
{"Guam" ,"GU" , "1" , 10 , "011" },
{"Guatemala" ,"GT" , "502" , 8 , "00" },
{"Guinea" ,"GN" , "224" , 8 , "00" },
{"Guinea-Bissau" ,"GW" , "245" , 7 , "00" },
{"Guyana" ,"GY" , "592" , 7 , "001" },
{"Haiti" ,"HT" , "509" , 8 , "00" },
{"Honduras" ,"HN" , "504" , 8 , "00" },
{"Hong Kong" ,"HK" , "852" , 8 , "001" },
{"Hungary" ,"HU" , "36" , 9 , "00" },
{"Iceland" ,"IS" , "354" , 9 , "00" },
{"India" ,"IN" , "91" , 10 , "00" },
{"Indonesia" ,"ID" , "62" , 12 , "001" },
{"Iran" ,"IR" , "98" , 10 , "00" },
{"Iraq" ,"IQ" , "964" , 10 , "00" },
{"Ireland" ,"IE" , "353" , 9 , "00" },
{"Israel" ,"IL" , "972" , 9 , "00" },
{"Italy" ,"IT" , "39" , 10 , "00" },
/* {"Jersey" ,"JE" , "44" , 10 , "00" },*/
{"Jamaica" ,"JM" , "1" , 10 , "011" },
{"Japan" ,"JP" , "81" , 10 , "010" },
{"Jordan" ,"JO" , "962" , 9 , "00" },
{"Kazakhstan" ,"KZ" , "7" , 10 , "00" },
{"Kenya" ,"KE" , "254" , 9 , "000" },
{"Kiribati" ,"KI" , "686" , 5 , "00" },
{"Korea, North" ,"KP" , "850" , 12 , "99" },
{"Korea, South" ,"KR" , "82" , 12 , "001" },
{"Kuwait" ,"KW" , "965" , 8 , "00" },
{"Kyrgyzstan" ,"KG" , "996" , 9 , "00" },
{"Laos" ,"LA" , "856" , 10 , "00" },
{"Latvia" ,"LV" , "371" , 8 , "00" },
{"Lebanon" ,"LB" , "961" , 7 , "00" },
{"Lesotho" ,"LS" , "266" , 8 , "00" },
{"Liberia" ,"LR" , "231" , 8 , "00" },
{"Libya" ,"LY" , "218" , 8 , "00" },
{"Liechtenstein" ,"LI" , "423" , 7 , "00" },
{"Lithuania" ,"LT" , "370" , 8 , "00" },
{"Luxembourg" ,"LU" , "352" , 9 , "00" },
{"Macau" ,"MO" , "853" , 8 , "00" },
{"Macedonia" ,"MK" , "389" , 8 , "00" },
{"Madagascar" ,"MG" , "261" , 9 , "00" },
{"Malawi" ,"MW" , "265" , 9 , "00" },
{"Malaysia" ,"MY" , "60" , 9 , "00" },
{"Maldives" ,"MV" , "960" , 7 , "00" },
{"Mali" ,"ML" , "223" , 8 , "00" },
{"Malta" ,"MT" , "356" , 8 , "00" },
{"Marshall Islands" ,"MH" , "692" , 7 , "011" },
{"Martinique" ,"MQ" , "596" , 9 , "00" },
{"Mauritania" ,"MR" , "222" , 8 , "00" },
{"Mauritius" ,"MU" , "230" , 7 , "00" },
{"Mayotte Island" ,"YT" , "262" , 9 , "00" },
{"Mexico" ,"MX" , "52" , 10 , "00" },
/*The following is a pseudo dial plan for Mexican mobile phones. See https://en.wikipedia.org/wiki/Telephone_numbers_in_Mexico*/
{"Mexico" ,"MX" , "521" , 10 , "00" },
{"Micronesia" ,"FM" , "691" , 7 , "011" },
{"Moldova" ,"MD" , "373" , 8 , "00" },
{"Monaco" ,"MC" , "377" , 8 , "00" },
{"Mongolia" ,"MN" , "976" , 8 , "001" },
{"Montenegro" ,"ME" , "382" , 8 , "00" },
{"Montserrat" ,"MS" , "664" , 10 , "011" },
{"Morocco" ,"MA" , "212" , 9 , "00" },
{"Mozambique" ,"MZ" , "258" , 9 , "00" },
{"Myanmar" ,"MM" , "95" , 10 , "00" },
{"Namibia" ,"NA" , "264" , 9 , "00" },
{"Nauru" ,"NR" , "674" , 7 , "00" },
{"Nepal" ,"NP" , "43" , 10 , "00" },
{"Netherlands" ,"NL" , "31" , 9 , "00" },
{"New Caledonia" ,"NC" , "687" , 6 , "00" },
{"New Zealand" ,"NZ" , "64" , 8 , "00" },
{"Nicaragua" ,"NI" , "505" , 8 , "00" },
{"Niger" ,"NE" , "227" , 8 , "00" },
{"Nigeria" ,"NG" , "234" , 10 , "009" },
{"Niue" ,"NU" , "683" , 4 , "00" },
{"Norfolk Island" ,"NF" , "672" , 5 , "00" },
{"Northern Mariana Islands" ,"MP" , "1" , 10 , "011" },
{"Norway" ,"NO" , "47" , 8 , "00" },
{"Oman" ,"OM" , "968" , 8 , "00" },
{"Pakistan" ,"PK" , "92" , 10 , "00" },
{"Palau" ,"PW" , "680" , 7 , "011" },
{"Palestine" ,"PS" , "970" , 9 , "00" },
{"Panama" ,"PA" , "507" , 8 , "00" },
{"Papua New Guinea" ,"PG" , "675" , 8 , "00" },
{"Paraguay" ,"PY" , "595" , 9 , "00" },
{"Peru" ,"PE" , "51" , 9 , "00" },
{"Philippines" ,"PH" , "63" , 10 , "00" },
{"Poland" ,"PL" , "48" , 9 , "00" },
{"Portugal" ,"PT" , "351" , 9 , "00" },
{"Puerto Rico" ,"PR" , "1" , 10 , "011" },
{"Qatar" ,"QA" , "974" , 8 , "00" },
{"R<EFBFBD>union Island" ,"RE" , "262" , 9 , "011" },
{"Romania" ,"RO" , "40" , 9 , "00" },
{"Russian Federation" ,"RU" , "7" , 10 , "8" },
{"Rwanda" ,"RW" , "250" , 9 , "00" },
{"Saint Helena" ,"SH" , "290" , 4 , "00" },
{"Saint Kitts and Nevis" ,"KN" , "1" , 10 , "011" },
{"Saint Lucia" ,"LC" , "1" , 10 , "011" },
{"Saint Pierre and Miquelon" ,"PM" , "508" , 6 , "00" },
{"Saint Vincent and the Grenadines","VC" , "1" , 10 , "011" },
{"Samoa" ,"WS" , "685" , 7 , "0" },
{"San Marino" ,"SM" , "378" , 10 , "00" },
{"Sao Tome and Principe" ,"ST" , "239" , 7 , "00" },
{"Saudi Arabia" ,"SA" , "966" , 9 , "00" },
{"Senegal" ,"SN" , "221" , 9 , "00" },
{"Serbia" ,"RS" , "381" , 9 , "00" },
{"Seychelles" ,"SC" , "248" , 7 , "00" },
{"Sierra Leone" ,"SL" , "232" , 8 , "00" },
{"Singapore" ,"SG" , "65" , 8 , "001" },
{"Slovakia" ,"SK" , "421" , 9 , "00" },
{"Slovenia" ,"SI" , "386" , 8 , "00" },
{"Solomon Islands" ,"SB" , "677" , 7 , "00" },
{"Somalia" ,"SO" , "252" , 8 , "00" },
{"South Africa" ,"ZA" , "27" , 9 , "00" },
{"Spain" ,"ES" , "34" , 9 , "00" },
{"Sri Lanka" ,"LK" , "94" , 9 , "00" },
{"Sudan" ,"SD" , "249" , 9 , "00" },
{"Suriname" ,"SR" , "597" , 7 , "00" },
{"Swaziland" ,"SZ" , "268" , 8 , "00" },
{"Sweden" ,"SE" , "46" , 9 , "00" },
{"Switzerland" ,"XK" , "41" , 9 , "00" },
{"Syria" ,"SY" , "963" , 9 , "00" },
{"Taiwan" ,"TW" , "886" , 9 , "810" },
{"Tajikistan" ,"TJ" , "992" , 9 , "002" },
{"Tanzania" ,"TZ" , "255" , 9 , "000" },
{"Thailand" ,"TH" , "66" , 9 , "001" },
{"Togo" ,"TG" , "228" , 8 , "00" },
{"Tokelau" ,"TK" , "690" , 4 , "00" },
{"Tonga" ,"TO" , "676" , 5 , "00" },
{"Trinidad and Tobago" ,"TT" , "1" , 10 , "011" },
{"Tunisia" ,"TN" , "216" , 8 , "00" },
{"Turkey" ,"TR" , "90" , 10 , "00" },
{"Turkmenistan" ,"TM" , "993" , 8 , "00" },
{"Turks and Caicos Islands" ,"TC" , "1" , 7 , "0" },
{"Tuvalu" ,"TV" , "688" , 5 , "00" },
{"Uganda" ,"UG" , "256" , 9 , "000" },
{"Ukraine" ,"UA" , "380" , 9 , "00" },
{"United Arab Emirates" ,"AE" , "971" , 9 , "00" },
{"United Kingdom" ,"GB" , "44" , 10 , "00" },
/* {"United Kingdom" ,"UK" , "44" , 10 , "00" },*/
{"United States" ,"US" , "1" , 10 , "011" },
{"Uruguay" ,"UY" , "598" , 8 , "00" },
{"Uzbekistan" ,"UZ" , "998" , 9 , "8" },
{"Vanuatu" ,"VU" , "678" , 7 , "00" },
{"Venezuela" ,"VE" , "58" , 10 , "00" },
{"Vietnam" ,"VN" , "84" , 9 , "00" },
{"Wallis and Futuna" ,"WF" , "681" , 5 , "00" },
{"Yemen" ,"YE" , "967" , 9 , "00" },
{"Zambia" ,"ZM" , "260" , 9 , "00" },
{"Zimbabwe" ,"ZW" , "263" , 9 , "00" },
{NULL ,NULL , "" , 0 , NULL }
};
static LinphoneDialPlan most_common_dialplan={ "generic" ,"", "", 10, "00"};
int linphone_dial_plan_lookup_ccc_from_e164(const char* e164) {
LinphoneDialPlan* dial_plan;
LinphoneDialPlan* elected_dial_plan=NULL;
unsigned int found;
unsigned int i=0;
if (e164[0]!='+') {
return -1;/*not an e164 number*/
}
if (e164[1]=='1') {
/*USA case*/
return 1;
}
do {
found=0;
i++;
for (dial_plan=(LinphoneDialPlan*)dial_plans; dial_plan->country!=NULL; dial_plan++) {
if (strncmp(dial_plan->ccc,&e164[1],i) == 0) {
elected_dial_plan=dial_plan;
found++;
}
}
} while ((found>1 || found==0) && i < sizeof(dial_plan->ccc));
if (found==1) {
return atoi(elected_dial_plan->ccc);
} else {
return -1; /*not found */
}
}
int linphone_dial_plan_lookup_ccc_from_iso(const char* iso) {
LinphoneDialPlan* dial_plan;
for (dial_plan=(LinphoneDialPlan*)dial_plans; dial_plan->country!=NULL; dial_plan++) {
if (strcmp(iso, dial_plan->iso_country_code)==0) {
return atoi(dial_plan->ccc);
}
}
return -1;
}
const LinphoneDialPlan* linphone_dial_plan_by_ccc_as_int(int ccc) {
int i;
char ccc_as_char[16] = {0};
snprintf(ccc_as_char,sizeof(ccc_as_char)-1,"%i",ccc);
for(i=0;dial_plans[i].country!=NULL;++i){
if (strcmp(ccc_as_char,dial_plans[i].ccc)==0){
return &dial_plans[i];
}
}
/*else return a generic "most common" dial plan*/
return &most_common_dialplan;
}
const LinphoneDialPlan* linphone_dial_plan_by_ccc(const char *ccc) {
if (!ccc) {
return &most_common_dialplan;
}
return linphone_dial_plan_by_ccc_as_int((int)strtol(ccc,NULL,10));
}
const LinphoneDialPlan* linphone_dial_plan_get_all() {
return dial_plans;
}
bool_t linphone_dial_plan_is_generic(const LinphoneDialPlan *ccc) {
if (strcmp(ccc->country, most_common_dialplan.country) == 0)
return TRUE;
return FALSE;
}

View file

@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "mediastreamer2/dtmfgen.h"
#include "linphone/lpconfig.h"
#include "c-wrapper/c-wrapper.h"
static void ecc_init_filters(EcCalibrator *ecc){
@ -47,8 +47,8 @@ static void ecc_init_filters(EcCalibrator *ecc){
ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&ecc->rate);
ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_NCHANNELS,&channels);
ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_NCHANNELS,&ecc_channels);
ecc->det=ms_factory_create_filter(ecc->factory, MS_TONE_DETECTOR_ID);
ms_filter_call_method(ecc->det,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
ecc->rec=ms_factory_create_filter(ecc->factory, MS_VOID_SINK_ID);
@ -62,7 +62,7 @@ static void ecc_init_filters(EcCalibrator *ecc){
ms_filter_call_method(ecc->gen,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
ecc->write_resampler=ms_factory_create_filter(ecc->factory, MS_RESAMPLE_ID);
ecc->sndwrite=ms_snd_card_create_writer(ecc->play_card);
ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
ms_filter_call_method(ecc->sndwrite,MS_FILTER_GET_SAMPLE_RATE,&rate);
ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_NCHANNELS,&ecc_channels);
@ -153,37 +153,37 @@ static void on_tone_received(void *data, MSFilter *f, unsigned int event_id, voi
static void ecc_play_tones(EcCalibrator *ecc){
MSDtmfGenCustomTone tone;
MSToneDetectorDef expected_tone;
memset(&tone,0,sizeof(tone));
memset(&expected_tone,0,sizeof(expected_tone));
ms_filter_add_notify_callback(ecc->det,on_tone_received,ecc,TRUE);
/* configure the tones to be scanned */
strncpy(expected_tone.tone_name,"freq1",sizeof(expected_tone.tone_name));
expected_tone.frequency=(int)2349.32;
expected_tone.min_duration=40;
expected_tone.min_amplitude=0.1f;
ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
strncpy(expected_tone.tone_name,"freq2",sizeof(expected_tone.tone_name));
expected_tone.frequency=(int)2637.02;
expected_tone.min_duration=40;
expected_tone.min_amplitude=0.1f;
ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
strncpy(expected_tone.tone_name,"freq3",sizeof(expected_tone.tone_name));
expected_tone.frequency=(int)2093;
expected_tone.min_duration=40;
expected_tone.min_amplitude=0.1f;
ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
/*play an initial tone to startup the audio playback/capture*/
tone.frequencies[0]=140;
tone.duration=1000;
tone.amplitude=0.5;
@ -192,23 +192,23 @@ static void ecc_play_tones(EcCalibrator *ecc){
ms_sleep(2);
ms_filter_add_notify_callback(ecc->gen,on_tone_sent,ecc,TRUE);
/* play the three tones*/
if (ecc->play_cool_tones){
strncpy(tone.tone_name, "D", sizeof(tone.tone_name));
tone.frequencies[0]=(int)2349.32;
tone.duration=100;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_usleep(300000);
strncpy(tone.tone_name, "E", sizeof(tone.tone_name));
tone.frequencies[0]=(int)2637.02;
tone.duration=100;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_usleep(300000);
strncpy(tone.tone_name, "C", sizeof(tone.tone_name));
tone.frequencies[0]=(int)2093;
tone.duration=100;
@ -220,20 +220,20 @@ static void ecc_play_tones(EcCalibrator *ecc){
tone.duration=100;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_usleep(300000);
strncpy(tone.tone_name, "D", sizeof(tone.tone_name));
tone.frequencies[0]=(int)2349.32;
tone.duration=100;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_usleep(300000);
strncpy(tone.tone_name, "E", sizeof(tone.tone_name));
tone.frequencies[0]=(int)2637.02;
tone.duration=100;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_usleep(300000);
}
/*these two next ones are for lyrism*/
if (ecc->play_cool_tones){
tone.tone_name[0]='\0';
@ -241,15 +241,15 @@ static void ecc_play_tones(EcCalibrator *ecc){
tone.duration=400;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
ms_usleep(300000);
tone.tone_name[0]='\0';
tone.frequencies[0]=(int)1567.98;
tone.duration=400;
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
}
ms_sleep(1);
if (ecc->freq1 && ecc->freq2 && ecc->freq3) {
int delay=(int)(ecc->acc/3);
if (delay<0){
@ -274,7 +274,7 @@ static void ecc_play_tones(EcCalibrator *ecc){
static void * ecc_thread(void *p){
EcCalibrator *ecc=(EcCalibrator*)p;
ecc_init_filters(ecc);
ecc_play_tones(ecc);
ecc_deinit_filters(ecc);
@ -318,10 +318,59 @@ int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibration
ms_error("Echo calibration is still on going !");
return -1;
}
rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000);
rate = (unsigned int)lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000);
lc->ecc=ec_calibrator_new(lc->factory, lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,rate,cb,audio_init_cb,audio_uninit_cb,cb_data);
lc->ecc->play_cool_tones = lp_config_get_int(lc->config, "sound", "ec_calibrator_cool_tones", 0);
lc->ecc->play_cool_tones = !!lp_config_get_int(lc->config, "sound", "ec_calibrator_cool_tones", 0);
ec_calibrator_start(lc->ecc);
return 0;
}
static void _ec_calibration_result_cb(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *user_data) {
linphone_core_notify_ec_calibration_result(lc, status, delay_ms);
}
static void _ec_calibration_audio_init_cb(void *user_data) {
LinphoneCore *lc = (LinphoneCore *)user_data;
linphone_core_notify_ec_calibration_audio_init(lc);
}
static void _ec_calibration_audio_uninit_cb(void *user_data) {
LinphoneCore *lc = (LinphoneCore *)user_data;
linphone_core_notify_ec_calibration_audio_uninit(lc);
}
LinphoneStatus linphone_core_start_echo_canceller_calibration(LinphoneCore *lc) {
unsigned int rate;
if (lc->ecc!=NULL){
ms_error("Echo calibration is still on going !");
return -1;
}
rate = (unsigned int)lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000);
lc->ecc=ec_calibrator_new(lc->factory, lc->sound_conf.play_sndcard, lc->sound_conf.capt_sndcard, rate,
_ec_calibration_result_cb,
_ec_calibration_audio_init_cb,
_ec_calibration_audio_uninit_cb, lc);
lc->ecc->play_cool_tones = !!lp_config_get_int(lc->config, "sound", "ec_calibrator_cool_tones", 0);
ec_calibrator_start(lc->ecc);
return 0;
}
bool_t linphone_core_has_builtin_echo_canceller(LinphoneCore *lc) {
MSFactory * factory = linphone_core_get_ms_factory(lc);
MSDevicesInfo *devices = ms_factory_get_devices_info(factory);
SoundDeviceDescription *sound_description = ms_devices_info_get_sound_device_description(devices);
if (sound_description == NULL) return FALSE;
if (sound_description->flags & DEVICE_HAS_BUILTIN_AEC) return TRUE;
return FALSE;
}
bool_t linphone_core_is_echo_canceller_calibration_required(LinphoneCore *lc) {
MSFactory * factory = linphone_core_get_ms_factory(lc);
MSDevicesInfo *devices = ms_factory_get_devices_info(factory);
SoundDeviceDescription *sound_description = ms_devices_info_get_sound_device_description(devices);
if (sound_description == NULL) return TRUE;
if (sound_description->flags & DEVICE_HAS_BUILTIN_AEC) return FALSE;
if (sound_description->delay != 0) return FALSE;
return TRUE;
}

View file

@ -32,7 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
static char *create_enum_domain(const char *number){
long len=(long)strlen(number);
char *domain=reinterpret_cast<char *>(ms_malloc((len*2)+10));
char *domain=reinterpret_cast<char *>(ms_malloc((size_t)(len*2)+10));
long i,j;
for (i=0,j=len-1;j>=0;j--){

View file

@ -18,12 +18,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/core.h"
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneErrorInfo);
static void linphone_error_info_reset(LinphoneErrorInfo *ei);
static void error_info_destroy(LinphoneErrorInfo *ei){
@ -182,7 +184,7 @@ void linphone_error_info_from_sal_reason_ei(LinphoneErrorInfo *ei, const SalErro
linphone_error_info_from_sal(ei, reason_ei);
return;
}
if (ei->sub_ei){
if (reason_ei->reason == SalReasonNone){
linphone_error_info_unref(ei->sub_ei);
@ -198,16 +200,16 @@ void linphone_error_info_from_sal_reason_ei(LinphoneErrorInfo *ei, const SalErro
}
}
void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const SalOp *op){
void linphone_error_info_from_sal_op(LinphoneErrorInfo *ei, const LinphonePrivate::SalOp *op){
if (op==NULL) {
/*leave previous values in LinphoneErrorInfo, the op may have been released already.*/
return;
}else{
const SalErrorInfo *sei;
linphone_error_info_reset(ei);
sei = sal_op_get_error_info(op);
sei = op->getErrorInfo();
linphone_error_info_from_sal(ei, sei);
sei = sal_op_get_reason_error_info(op);
sei = op->getReasonErrorInfo();
linphone_error_info_from_sal_reason_ei(ei, sei);
}
}
@ -220,12 +222,12 @@ void linphone_error_info_fields_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo
sei->protocol_code = ei->protocol_code;
sei->protocol = bctbx_strdup(ei->protocol);
}
void linphone_error_info_to_sal(const LinphoneErrorInfo* ei, SalErrorInfo* sei){
linphone_error_info_fields_to_sal(ei, sei);
if (ei->sub_ei !=NULL) {
linphone_error_info_to_sal(ei->sub_ei, sei->sub_sei);
}
}

View file

@ -18,8 +18,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/event.h"
#include "private.h"
#include "linphone/lpconfig.h"
#include "sal/event-op.h"
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
using namespace LinphonePrivate;
const char * linphone_subscription_dir_to_string(LinphoneSubscriptionDir dir){
switch(dir){
@ -69,41 +76,84 @@ LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishStat
return NULL;
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneEventCbs);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneEventCbs, belle_sip_object_t,
NULL, // destroy
NULL, // clone
NULL, // marshal
FALSE
);
static LinphoneEventCbs *linphone_event_cbs_new(void) {
return belle_sip_object_new(LinphoneEventCbs);
}
LinphoneEventCbs *linphone_event_cbs_ref(LinphoneEventCbs *cbs) {
belle_sip_object_ref(cbs);
return cbs;
}
void linphone_event_cbs_unref(LinphoneEventCbs *cbs) {
belle_sip_object_unref(cbs);
}
void *linphone_event_cbs_get_user_data(const LinphoneEventCbs *cbs) {
return cbs->user_data;
}
void linphone_event_cbs_set_user_data(LinphoneEventCbs *cbs, void *ud) {
cbs->user_data = ud;
}
LinphoneEventCbsNotifyResponseCb linphone_event_cbs_get_notify_response(const LinphoneEventCbs *cbs) {
return cbs->notify_response_cb;
}
void linphone_event_cbs_set_notify_response(LinphoneEventCbs *cbs, LinphoneEventCbsNotifyResponseCb cb) {
cbs->notify_response_cb = cb;
}
static void linphone_event_release(LinphoneEvent *lev){
if (lev->op) {
/*this will stop the refresher*/
sal_op_stop_refreshing(lev->op);
lev->op->stopRefreshing();
}
linphone_event_unref(lev);
}
static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, SalOp *op){
static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, LinphonePrivate::SalEventOp *op){
LinphoneEvent *lev=belle_sip_object_new(LinphoneEvent);
lev->callbacks = linphone_event_cbs_new();
lev->lc=lc;
lev->dir=dir;
lev->op=op;
lev->name=ms_strdup(name);
sal_op_set_user_pointer(lev->op,lev);
if (strcmp(lev->name, "conference") == 0)
lev->internal = TRUE;
lev->op->setUserPointer(lev);
return lev;
}
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires){
LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, sal_op_new(lc->sal));
LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, new SalSubscribeOp(lc->sal));
lev->expires=expires;
return lev;
}
static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name, bool_t is_out_of_dialog){
static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalEventOp *op, LinphoneSubscriptionDir dir, const char *name, bool_t is_out_of_dialog){
LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, op);
lev->is_out_of_dialog_op=is_out_of_dialog;
return lev;
}
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) {
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalEventOp *op, LinphoneSubscriptionDir dir, const char *name) {
return linphone_event_new_with_op_base(lc,op,dir,name,FALSE);
}
LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) {
LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalEventOp *op, LinphoneSubscriptionDir dir, const char *name) {
return linphone_event_new_with_op_base(lc,op,dir,name,TRUE);
}
@ -171,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);
sal_op_set_manual_refresher_mode(lev->op,!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;
}
@ -179,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;
sal_op_set_event(lev->op, event);
lev->op->setEvent(event);
lev->is_out_of_dialog_op = TRUE;
return lev;
}
@ -215,13 +265,14 @@ LinphoneStatus linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneC
}
if (lev->send_custom_headers){
sal_op_set_sent_custom_header(lev->op,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 sal_op_set_sent_custom_header(lev->op,NULL);
}else lev->op->setSentCustomHeaders(NULL);
body_handler = sal_body_handler_from_content(body);
err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,body_handler);
auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
err=subscribeOp->subscribe(NULL,NULL,lev->name,lev->expires,body_handler);
if (err==0){
if (lev->subscription_state==LinphoneSubscriptionNone)
linphone_event_set_state(lev,LinphoneSubscriptionOutgoingProgress);
@ -234,7 +285,7 @@ LinphoneStatus linphone_event_update_subscribe(LinphoneEvent *lev, const Linphon
}
LinphoneStatus linphone_event_refresh_subscribe(LinphoneEvent *lev) {
return sal_op_refresh(lev->op);
return lev->op->refresh();
}
LinphoneStatus linphone_event_accept_subscription(LinphoneEvent *lev){
@ -243,7 +294,8 @@ LinphoneStatus linphone_event_accept_subscription(LinphoneEvent *lev){
ms_error("linphone_event_accept_subscription(): cannot accept subscription if subscription wasn't just received.");
return -1;
}
err=sal_subscribe_accept(lev->op);
auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
err=subscribeOp->accept();
if (err==0){
linphone_event_set_state(lev,LinphoneSubscriptionActive);
}
@ -256,7 +308,8 @@ LinphoneStatus linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReas
ms_error("linphone_event_deny_subscription(): cannot deny subscription if subscription wasn't just received.");
return -1;
}
err=sal_subscribe_decline(lev->op,linphone_reason_to_sal(reason));
auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
err=subscribeOp->decline(linphone_reason_to_sal(reason));
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
return err;
}
@ -271,14 +324,15 @@ 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);
return sal_notify(lev->op, body_handler);
body_handler = sal_body_handler_from_content(body, false);
auto subscribeOp = dynamic_cast<SalSubscribeOp *>(lev->op);
return subscribeOp->notify(body_handler);
}
static LinphoneEvent *_linphone_core_create_publish(LinphoneCore *core, LinphoneProxyConfig *cfg, const LinphoneAddress *resource, const char *event, int expires){
LinphoneCore *lc = core;
LinphoneEvent *lev;
if (!lc && cfg) {
if (cfg->lc)
lc = cfg->lc;
@ -289,20 +343,21 @@ static LinphoneEvent *_linphone_core_create_publish(LinphoneCore *core, Linphone
}
if (!resource && cfg)
resource = linphone_proxy_config_get_identity_address(cfg);
lev = linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event,expires);
linphone_configure_op_with_proxy(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0),cfg);
sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1));
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->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){
return _linphone_core_create_publish(lc, NULL, resource, event, expires);
}
LinphoneEvent *linphone_proxy_config_create_publish(LinphoneProxyConfig *cfg, const char *event, int expires) {
return _linphone_core_create_publish(NULL, cfg,NULL, event, expires);
}
LinphoneEvent *linphone_core_create_one_shot_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event){
LinphoneEvent *lev = linphone_core_create_publish(lc, resource, event, -1);
@ -319,12 +374,13 @@ static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneConten
return -1;
}
if (lev->send_custom_headers){
sal_op_set_sent_custom_header(lev->op,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 sal_op_set_sent_custom_header(lev->op,NULL);
}else lev->op->setSentCustomHeaders(NULL);
body_handler = sal_body_handler_from_content(body);
err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,body_handler);
auto publishOp = dynamic_cast<SalPublishOp *>(lev->op);
err=publishOp->publish(NULL,NULL,lev->name,lev->expires,body_handler);
if (err==0){
linphone_event_set_publish_state(lev,LinphonePublishProgress);
}else if (notify_err){
@ -354,14 +410,17 @@ LinphoneStatus linphone_event_update_publish(LinphoneEvent* lev, const LinphoneC
}
LinphoneStatus linphone_event_refresh_publish(LinphoneEvent *lev) {
return sal_op_refresh(lev->op);
return lev->op->refresh();
}
void linphone_event_pause_publish(LinphoneEvent *lev) {
if (lev->op) sal_op_stop_refreshing(lev->op);
if (lev->op) lev->op->stopRefreshing();
}
void linphone_event_unpublish(LinphoneEvent *lev) {
lev->terminating = TRUE; /* needed to get clear event*/
if (lev->op) sal_op_unpublish(lev->op);
if (lev->op) {
auto op = dynamic_cast<SalPublishOp *>(lev->op);
op->unpublish();
}
}
void linphone_event_set_user_data(LinphoneEvent *ev, void *up){
ev->userdata=up;
@ -376,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=sal_op_get_recv_custom_header(ev->op);
const SalCustomHeader *ch=ev->op->getRecvCustomHeaders();
return sal_custom_header_find(ch,name);
}
@ -392,16 +451,18 @@ void linphone_event_terminate(LinphoneEvent *lev){
}
lev->terminating=TRUE;
if (lev->dir==LinphoneSubscriptionIncoming){
sal_notify_close(lev->op);
auto op = dynamic_cast<SalSubscribeOp *>(lev->op);
op->closeNotify();
}else if (lev->dir==LinphoneSubscriptionOutgoing){
sal_unsubscribe(lev->op);
auto op = dynamic_cast<SalSubscribeOp *>(lev->op);
op->unsubscribe();
}
if (lev->publish_state!=LinphonePublishNone){
if (lev->publish_state==LinphonePublishOk && lev->expires!=-1){
sal_op_unpublish(lev->op);
auto op = dynamic_cast<SalPublishOp *>(lev->op);
op->unpublish();
}
linphone_event_set_publish_state(lev,LinphonePublishCleared);
return;
@ -421,8 +482,13 @@ LinphoneEvent *linphone_event_ref(LinphoneEvent *lev){
static void linphone_event_destroy(LinphoneEvent *lev){
if (lev->ei) linphone_error_info_unref(lev->ei);
if (lev->op) sal_op_release(lev->op);
if (lev->op) lev->op->release();
if (lev->send_custom_headers) sal_custom_header_free(lev->send_custom_headers);
if (lev->to_address) linphone_address_unref(lev->to_address);
if (lev->from_address) linphone_address_unref(lev->from_address);
if (lev->remote_contact_address) linphone_address_unref(lev->remote_contact_address);
linphone_event_cbs_unref(lev->callbacks);
ms_free(lev->name);
}
@ -442,20 +508,47 @@ const char *linphone_event_get_name(const LinphoneEvent *lev){
return lev->name;
}
const LinphoneAddress *linphone_event_get_from(const LinphoneEvent *lev){
if (lev->is_out_of_dialog_op && lev->dir == LinphoneSubscriptionOutgoing){
return (LinphoneAddress*)sal_op_get_to_address(lev->op);
}else{
return (LinphoneAddress*)sal_op_get_from_address(lev->op);
}
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->getToAddress());
((LinphoneEvent *)lev)->to_address = linphone_address_new(buf);
ms_free(buf);
return lev->to_address;
}
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->getFromAddress());
((LinphoneEvent *)lev)->from_address = linphone_address_new(buf);
ms_free(buf);
return lev->from_address;
}
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->getRemoteContactAddress());
((LinphoneEvent *)lev)->remote_contact_address = linphone_address_new(buf);
ms_free(buf);
return lev->remote_contact_address;
}
const LinphoneAddress *linphone_event_get_from (const LinphoneEvent *lev) {
if (lev->is_out_of_dialog_op && lev->dir == LinphoneSubscriptionOutgoing)
return _linphone_event_cache_to(lev);
return _linphone_event_cache_from(lev);
}
const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){
if (lev->is_out_of_dialog_op && lev->dir == LinphoneSubscriptionOutgoing){
return (LinphoneAddress*)sal_op_get_from_address(lev->op);
}else{
return (LinphoneAddress*)sal_op_get_to_address(lev->op);
}
if (lev->is_out_of_dialog_op && lev->dir == LinphoneSubscriptionOutgoing)
return _linphone_event_cache_from(lev);
return _linphone_event_cache_to(lev);
}
const LinphoneAddress *linphone_event_get_remote_contact (const LinphoneEvent *lev) {
return _linphone_event_cache_remote_contact(lev);
}
LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev){
@ -472,6 +565,16 @@ static belle_sip_error_code _linphone_event_marshall(belle_sip_object_t *obj, ch
return err;
}
void _linphone_event_notify_notify_response(const LinphoneEvent *lev) {
LinphoneEventCbsNotifyResponseCb cb = linphone_event_cbs_get_notify_response(lev->callbacks);
if (cb)
cb(lev);
}
LinphoneEventCbs *linphone_event_get_callbacks(const LinphoneEvent *ev) {
return ev->callbacks;
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneEvent);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneEvent, belle_sip_object_t,
@ -480,4 +583,3 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneEvent, belle_sip_object_t,
_linphone_event_marshall,
FALSE
);

View file

@ -18,17 +18,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/factory.h"
#include "c-wrapper/c-wrapper.h"
#include "address/address-p.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
#ifndef PACKAGE_SOUND_DIR
#define PACKAGE_SOUND_DIR "."
#define PACKAGE_SOUND_DIR "."
#endif
#ifndef PACKAGE_RING_DIR
#define PACKAGE_RING_DIR "."
#define PACKAGE_RING_DIR "."
#endif
#ifndef PACKAGE_DATA_DIR
#define PACKAGE_DATA_DIR "."
#define PACKAGE_DATA_DIR "."
#endif
extern LinphoneAddress *_linphone_address_new(const char *addr);
@ -55,6 +61,8 @@ struct _LinphoneFactory {
char *cached_image_resources_dir;
char *cached_msplugins_dir;
LinphoneErrorInfo* ei;
void *user_data;
};
static void linphone_factory_uninit(LinphoneFactory *obj){
@ -139,33 +147,83 @@ LinphoneFactory *linphone_factory_get(void) {
}
void linphone_factory_clean(void){
LinphonePrivate::AddressPrivate::clearSipAddressesCache();
if (_factory){
belle_sip_object_unref(_factory);
_factory = NULL;
}
}
LinphoneCore *linphone_factory_create_core_2(const LinphoneFactory *factory, LinphoneCoreCbs *cbs,
const char *config_path, const char *factory_config_path, void *user_data, void *system_context) {
static LinphoneCore *_linphone_factory_create_core (
const LinphoneFactory *factory,
LinphoneCoreCbs *cbs,
const char *config_path,
const char *factory_config_path,
void *user_data,
void *system_context,
bool_t automatically_start
) {
bctbx_init_logger(FALSE);
LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path);
LinphoneCore *lc = _linphone_core_new_with_config(cbs, config, user_data, system_context);
LinphoneCore *lc = _linphone_core_new_with_config(cbs, config, user_data, system_context, automatically_start);
lp_config_unref(config);
bctbx_uninit_logger();
return lc;
}
LinphoneCore *linphone_factory_create_core(const LinphoneFactory *factory, LinphoneCoreCbs *cbs,
const char *config_path, const char *factory_config_path){
return linphone_factory_create_core_2(factory, cbs, config_path, factory_config_path, NULL, NULL);
LinphoneCore *linphone_factory_create_core (
const LinphoneFactory *factory,
LinphoneCoreCbs *cbs,
const char *config_path,
const char *factory_config_path
) {
return _linphone_factory_create_core(factory, cbs, config_path, factory_config_path, NULL, NULL, TRUE);
}
LinphoneCore *linphone_factory_create_core_with_config(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, LinphoneConfig *config) {
return _linphone_core_new_with_config(cbs, config, NULL, NULL);
LinphoneCore *linphone_factory_create_core_2 (
const LinphoneFactory *factory,
LinphoneCoreCbs *cbs,
const char *config_path,
const char *factory_config_path,
void *user_data,
void *system_context
) {
return _linphone_factory_create_core(factory, cbs, config_path, factory_config_path, user_data, system_context, TRUE);
}
LinphoneCore *linphone_factory_create_core_with_config_2(const LinphoneFactory *factory, LinphoneCoreCbs *cbs, LinphoneConfig *config, void *user_data, void *system_context) {
return _linphone_core_new_with_config(cbs, config, user_data, system_context);
LinphoneCore *linphone_factory_create_core_3 (
const LinphoneFactory *factory,
const char *config_path,
const char *factory_config_path,
void *system_context
) {
return _linphone_factory_create_core(factory, NULL, config_path, factory_config_path, NULL, system_context, FALSE);
}
LinphoneCore *linphone_factory_create_core_with_config (
const LinphoneFactory *factory,
LinphoneCoreCbs *cbs,
LinphoneConfig *config
) {
return _linphone_core_new_with_config(cbs, config, NULL, NULL, TRUE);
}
LinphoneCore *linphone_factory_create_core_with_config_2 (
const LinphoneFactory *factory,
LinphoneCoreCbs *cbs,
LinphoneConfig *config,
void *user_data,
void *system_context
) {
return _linphone_core_new_with_config(cbs, config, user_data, system_context, TRUE);
}
LinphoneCore *linphone_factory_create_core_with_config_3 (
const LinphoneFactory *factory,
LinphoneConfig *config,
void *system_context
) {
return _linphone_core_new_with_config(NULL, config, NULL, system_context, FALSE);
}
LinphoneCoreCbs *linphone_factory_create_core_cbs(const LinphoneFactory *factory) {
@ -173,7 +231,7 @@ LinphoneCoreCbs *linphone_factory_create_core_cbs(const LinphoneFactory *factory
}
LinphoneAddress *linphone_factory_create_address(const LinphoneFactory *factory, const char *addr) {
return _linphone_address_new(addr);
return linphone_address_new(addr);
}
LinphoneAuthInfo *linphone_factory_create_auth_info(const LinphoneFactory *factory, const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain) {
@ -184,6 +242,10 @@ LinphoneCallCbs * linphone_factory_create_call_cbs(const LinphoneFactory *factor
return _linphone_call_cbs_new();
}
LinphoneChatRoomCbs * linphone_factory_create_chat_room_cbs(const LinphoneFactory *factory) {
return _linphone_chat_room_cbs_new();
}
LinphoneVcard *linphone_factory_create_vcard(LinphoneFactory *factory) {
return _linphone_vcard_new();
}
@ -329,3 +391,55 @@ LinphoneTransports *linphone_factory_create_transports(LinphoneFactory *factory)
LinphoneVideoActivationPolicy *linphone_factory_create_video_activation_policy(LinphoneFactory *factory) {
return linphone_video_activation_policy_new();
}
LinphoneContent *linphone_factory_create_content(LinphoneFactory *factory) {
return linphone_content_new();
}
LinphoneBuffer *linphone_factory_create_buffer(LinphoneFactory *factory) {
return linphone_buffer_new();
}
LinphoneBuffer *linphone_factory_create_buffer_from_data(LinphoneFactory *factory, const uint8_t *data, size_t size) {
return linphone_buffer_new_from_data(data, size);
}
LinphoneBuffer *linphone_factory_create_buffer_from_string(LinphoneFactory *factory, const char *data) {
return linphone_buffer_new_from_string(data);
}
LinphoneConfig *linphone_factory_create_config(LinphoneFactory *factory, const char *path) {
return linphone_config_new(path);
}
LinphoneConfig *linphone_factory_create_config_with_factory(LinphoneFactory *factory, const char *path, const char *factory_path) {
return linphone_config_new_with_factory(path, factory_path);
}
LinphoneConfig *linphone_factory_create_config_from_string(LinphoneFactory *factory, const char *data) {
return linphone_config_new_from_buffer(data);
}
const bctbx_list_t * linphone_factory_get_dial_plans(const LinphoneFactory *factory) {
return linphone_dial_plan_get_all_list();
}
void *linphone_factory_get_user_data(const LinphoneFactory *factory) {
return factory->user_data;
}
void linphone_factory_set_user_data(LinphoneFactory *factory, void *data) {
factory->user_data = data;
}
void linphone_factory_set_log_collection_path(LinphoneFactory *factory, const char *path) {
linphone_core_set_log_collection_path(path);
}
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

@ -23,65 +23,75 @@
*/
#include "linphone/core.h"
#include "private.h"
#include "linphone/lpconfig.h"
#ifdef SQLITE_STORAGE_ENABLED
#ifndef _WIN32
#if !defined(__ANDROID__) && !defined(__QNXNTO__)
# include <langinfo.h>
# include <iconv.h>
# include <string.h>
#endif
#ifndef _WIN32
#if !defined(__ANDROID__) && !defined(__QNXNTO__)
#include <langinfo.h>
#include <iconv.h>
#include <string.h>
#endif
#else
#include <Windows.h>
#include <Windows.h>
#endif
#define MAX_PATH_SIZE 1024
#include "sqlite3.h"
#include "sqlite3.h"
#endif
#include "c-wrapper/c-wrapper.h"
#include "core/core-p.h"
#include "db/main-db.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
using namespace std;
using namespace LinphonePrivate;
const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
const char *str=NULL;
switch(ss){
case LinphoneStatusOnline:
str=_("Online");
str="Online";
break;
case LinphoneStatusBusy:
str=_("Busy");
str="Busy";
break;
case LinphoneStatusBeRightBack:
str=_("Be right back");
str="Be right back";
break;
case LinphoneStatusAway:
str=_("Away");
str="Away";
break;
case LinphoneStatusOnThePhone:
str=_("On the phone");
str="On the phone";
break;
case LinphoneStatusOutToLunch:
str=_("Out to lunch");
str="Out to lunch";
break;
case LinphoneStatusDoNotDisturb:
str=_("Do not disturb");
str="Do not disturb";
break;
case LinphoneStatusMoved:
str=_("Moved");
str="Moved";
break;
case LinphoneStatusAltService:
str=_("Using another messaging service");
str="Using another messaging service";
break;
case LinphoneStatusOffline:
str=_("Offline");
str="Offline";
break;
case LinphoneStatusPending:
str=_("Pending");
str="Pending";
break;
case LinphoneStatusVacation:
str=_("Vacation");
str="Vacation";
break;
default:
str=_("Unknown status");
str="Unknown status";
}
return str;
}
@ -184,12 +194,12 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
*/
}else{
sal_op_release(fr->outsub);
fr->outsub->release();
fr->outsub=NULL;
}
fr->outsub=sal_op_new(lc->sal);
fr->outsub=new SalPresenceOp(lc->sal);
linphone_configure_op(lc,fr->outsub,addr,NULL,TRUE);
sal_subscribe_presence(fr->outsub,NULL,NULL,lp_config_get_int(lc->config,"sip","subscribe_expires",600));
fr->outsub->subscribe(NULL,NULL,lp_config_get_int(lc->config,"sip","subscribe_expires",600));
fr->subscribe_active=TRUE;
}
}
@ -403,7 +413,7 @@ void linphone_friend_add_phone_number(LinphoneFriend *lf, const char *phone) {
}
}
bctbx_list_t* linphone_friend_get_phone_numbers(LinphoneFriend *lf) {
bctbx_list_t* linphone_friend_get_phone_numbers(const LinphoneFriend *lf) {
if (!lf || !lf->vcard) return NULL;
if (linphone_core_vcard_supported()) {
@ -467,8 +477,8 @@ void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence)
}
}
for(elem=lf->insubs; elem!=NULL; elem=bctbx_list_next(elem)){
SalOp *op = (SalOp*)bctbx_list_get_data(elem);
sal_notify_presence(op,(SalPresenceModel *)presence);
auto op = reinterpret_cast<SalPresenceOp *>(bctbx_list_get_data(elem));
op->notifyPresence((SalPresenceModel *)presence);
}
}
@ -479,14 +489,14 @@ void linphone_friend_add_incoming_subscription(LinphoneFriend *lf, SalOp *op){
void linphone_friend_remove_incoming_subscription(LinphoneFriend *lf, SalOp *op){
if (bctbx_list_find(lf->insubs, op)){
sal_op_release(op);
op->release();
lf->insubs = bctbx_list_remove(lf->insubs, op);
}
}
static void linphone_friend_unsubscribe(LinphoneFriend *lf){
if (lf->outsub!=NULL) {
sal_unsubscribe(lf->outsub);
lf->outsub->unsubscribe();
}
/* for friend list there is no necessary outsub*/
lf->subscribe_active=FALSE;
@ -497,7 +507,7 @@ void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
LinphoneCore *lc=lf->lc;
if (lf->outsub!=NULL) {
sal_op_release(lf->outsub);
lf->outsub->release();
lf->outsub=NULL;
}
@ -520,13 +530,17 @@ void linphone_friend_invalidate_subscription(LinphoneFriend *lf){
lf->initial_subscribes_sent=FALSE;
}
static void sal_notify_presence_close_cb (void *op) {
sal_notify_presence_close(static_cast<SalOp *>(op));
static void close_presence_notification(SalPresenceOp *op) {
op->notifyPresenceClose();
}
static void release_sal_op(SalOp *op) {
op->release();
}
static void linphone_friend_close_incoming_subscriptions(LinphoneFriend *lf) {
bctbx_list_for_each(lf->insubs, sal_notify_presence_close_cb);
lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc)sal_op_release);
bctbx_list_for_each(lf->insubs, (MSIterateFunc) close_presence_notification);
lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc)release_sal_op);
}
void linphone_friend_close_subscriptions(LinphoneFriend *lf){
@ -535,9 +549,9 @@ void linphone_friend_close_subscriptions(LinphoneFriend *lf){
}
static void _linphone_friend_release_ops(LinphoneFriend *lf){
lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc) sal_op_release);
lf->insubs = bctbx_list_free_with_data(lf->insubs, (MSIterateFunc) release_sal_op);
if (lf->outsub){
sal_op_release(lf->outsub);
lf->outsub->release();
lf->outsub=NULL;
}
}
@ -759,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;
sal_op_stop_refreshing(fr->outsub);
fr->outsub->stopRefreshing();
}
}
@ -893,7 +907,7 @@ void linphone_core_update_friends_subscriptions(LinphoneCore *lc) {
}
bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc){
return lp_config_get_int(lc->config,"sip","subscribe_presence_only_when_registered",1);
return !!lp_config_get_int(lc->config,"sip","subscribe_presence_only_when_registered",1);
}
void linphone_core_send_initial_subscribes(LinphoneCore *lc) {
@ -1034,7 +1048,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde
linphone_friend_set_inc_subscribe_policy(lf,__policy_str_to_enum(tmp));
}
a=lp_config_get_int(config,item,"subscribe",0);
linphone_friend_send_subscribe(lf,a);
linphone_friend_send_subscribe(lf,!!a);
a = lp_config_get_int(config, item, "presence_received", 0);
lf->presence_received = (bool_t)a;
@ -1120,7 +1134,7 @@ void linphone_friend_destroy(LinphoneFriend *lf) {
linphone_friend_unref(lf);
}
LinphoneVcard* linphone_friend_get_vcard(LinphoneFriend *fr) {
LinphoneVcard* linphone_friend_get_vcard(const LinphoneFriend *fr) {
if (fr && linphone_core_vcard_supported()) return fr->vcard;
return NULL;
}
@ -1160,7 +1174,7 @@ bool_t linphone_friend_create_vcard(LinphoneFriend *fr, const char *name) {
lc = fr->friend_list->lc;
}
if (lc) {
skip = 1 - lp_config_get_int(fr->lc->config, "misc", "store_friends", 1);
skip = !lp_config_get_int(fr->lc->config, "misc", "store_friends", 1);
linphone_vcard_set_skip_validation(vcard, skip);
}
linphone_vcard_set_full_name(vcard, name);
@ -1262,13 +1276,13 @@ static bool_t linphone_update_friends_table(sqlite3* db) {
int database_user_version = -1;
char *errmsg = NULL;
if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &stmt_version, NULL) == SQLITE_OK) {
while(sqlite3_step(stmt_version) == SQLITE_ROW) {
database_user_version = sqlite3_column_int(stmt_version, 0);
if (sqlite3_prepare_v2(db, "PRAGMA user_version;", -1, &stmt_version, NULL) == SQLITE_OK) {
while(sqlite3_step(stmt_version) == SQLITE_ROW) {
database_user_version = sqlite3_column_int(stmt_version, 0);
ms_debug("friends database user version = %i", database_user_version);
}
}
sqlite3_finalize(stmt_version);
sqlite3_finalize(stmt_version);
if (database_user_version != 3100) { // Linphone 3.10.0
int ret = sqlite3_exec(db,
@ -1414,9 +1428,9 @@ static int create_friend(void *data, int argc, char **argv, char **colName) {
}
}
linphone_friend_set_inc_subscribe_policy(lf, static_cast<LinphoneSubscribePolicy>(atoi(argv[3])));
linphone_friend_send_subscribe(lf, atoi(argv[4]));
linphone_friend_send_subscribe(lf, !!atoi(argv[4]));
linphone_friend_set_ref_key(lf, ms_strdup(argv[5]));
lf->presence_received = atoi(argv[9]);
lf->presence_received = !!atoi(argv[9]);
lf->storage_id = storage_id;
*list = bctbx_list_append(*list, linphone_friend_ref(lf));
@ -1710,6 +1724,10 @@ bctbx_list_t* linphone_core_fetch_friends_lists_from_db(LinphoneCore *lc) {
#endif
void linphone_core_set_friends_database_path(LinphoneCore *lc, const char *path) {
if (!linphone_core_conference_server_enabled(lc))
L_GET_PRIVATE(lc->cppPtr)->mainDb->import(LinphonePrivate::MainDb::Sqlite3, path);
// TODO: Remove me later.
if (lc->friends_db_file){
ms_free(lc->friends_db_file);
lc->friends_db_file = NULL;
@ -1717,8 +1735,6 @@ void linphone_core_set_friends_database_path(LinphoneCore *lc, const char *path)
if (path) {
lc->friends_db_file = ms_strdup(path);
linphone_core_friends_storage_init(lc);
linphone_core_migrate_friends_from_rc_to_db(lc);
}
}
@ -1726,69 +1742,6 @@ const char* linphone_core_get_friends_database_path(LinphoneCore *lc) {
return lc->friends_db_file;
}
void linphone_core_migrate_friends_from_rc_to_db(LinphoneCore *lc) {
LpConfig *lpc = NULL;
LinphoneFriend *lf = NULL;
LinphoneFriendList *lfl = linphone_core_get_default_friend_list(lc);
int i;
#ifndef SQLITE_STORAGE_ENABLED
ms_warning("linphone has been compiled without sqlite, can't migrate friends");
return;
#endif
if (!lc) {
return;
}
lpc = linphone_core_get_config(lc);
if (!lpc) {
ms_warning("this core has been started without a rc file, nothing to migrate");
return;
}
if (lp_config_get_int(lpc, "misc", "friends_migration_done", 0) == 1) {
ms_warning("the friends migration has already been done, skipping...");
return;
}
if (bctbx_list_size(linphone_friend_list_get_friends(lfl)) > 0 && lfl->storage_id == 0) {
linphone_core_remove_friend_list(lc, lfl);
lfl = linphone_core_create_friend_list(lc);
linphone_core_add_friend_list(lc, lfl);
linphone_friend_list_unref(lfl);
}
for (i = 0; (lf = linphone_friend_new_from_config_file(lc, i)) != NULL; i++) {
char friend_section[32];
const LinphoneAddress *addr = linphone_friend_get_address(lf);
if (addr) {
char *address = NULL;
const char *displayName = linphone_address_get_display_name(addr);
if (!displayName) displayName = linphone_address_get_username(addr);
address = linphone_address_as_string(addr);
if (linphone_core_vcard_supported()) {
if (!linphone_friend_create_vcard(lf, displayName)) {
ms_warning("Couldn't create vCard for friend %s", address);
} else {
linphone_vcard_add_sip_address(linphone_friend_get_vcard(lf), address);
linphone_address_unref(lf->uri);
lf->uri = NULL;
}
}
ms_free(address);
linphone_friend_list_add_friend(lfl, lf);
linphone_friend_unref(lf);
snprintf(friend_section, sizeof(friend_section), "friend_%i", i);
lp_config_clean_section(lpc, friend_section);
}
}
ms_debug("friends migration successful: %i friends migrated", i);
lp_config_set_int(lpc, "misc", "friends_migration_done", 1);
}
LinphoneSubscriptionState linphone_friend_get_subscription_state(const LinphoneFriend *lf) {
return lf->out_sub_state;
}
@ -1826,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

@ -17,11 +17,16 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/core.h"
#include "private.h"
#include <bctoolbox/crypto.h>
#include "linphone/api/c-content.h"
#include "linphone/core.h"
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneFriendListCbs);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneFriendListCbs, belle_sip_object_t,
@ -461,14 +466,14 @@ const LinphoneAddress * _linphone_friend_list_get_rls_address(const LinphoneFrie
const char* rls_uri = lp_config_get_string(list->lc->config, "sip", "rls_uri", NULL);
if (list->lc->default_rls_addr)
linphone_address_unref(list->lc->default_rls_addr);
list->lc->default_rls_addr=NULL;
if (rls_uri) {
/*to make sure changes in config are used if any*/
list->lc->default_rls_addr = linphone_address_new(rls_uri);
}
return list->lc->default_rls_addr;
}
else
@ -476,7 +481,7 @@ const LinphoneAddress * _linphone_friend_list_get_rls_address(const LinphoneFrie
}
void linphone_friend_list_set_rls_address(LinphoneFriendList *list, const LinphoneAddress *rls_addr){
LinphoneAddress *new_rls_addr = rls_addr ? linphone_address_clone(rls_addr) : NULL;
if (list->rls_addr){
linphone_address_unref(list->rls_addr);
}
@ -572,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;
@ -630,10 +636,13 @@ static LinphoneFriendListStatus _linphone_friend_list_remove_friend(LinphoneFrie
list->friends = bctbx_list_erase_link(list->friends, elem);
if(lf->refkey) {
bctbx_iterator_t * it = bctbx_map_cchar_find_key(list->friends_map, lf->refkey);
if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(list->friends_map))){
bctbx_iterator_t * end = bctbx_map_cchar_end(list->friends_map);
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(list->friends_map, it);
}
if (it) bctbx_iterator_cchar_delete(it);
if (end) bctbx_iterator_cchar_delete(end);
}
phone_numbers = linphone_friend_get_phone_numbers(lf);
@ -643,14 +652,17 @@ static LinphoneFriendListStatus _linphone_friend_list_remove_friend(LinphoneFrie
const char *uri = linphone_friend_phone_number_to_sip_uri(lf, number);
if(uri) {
bctbx_iterator_t * it = bctbx_map_cchar_find_key(list->friends_map_uri, uri);
if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(list->friends_map_uri))){
bctbx_iterator_t * end = bctbx_map_cchar_end(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(list->friends_map_uri, it);
}
bctbx_iterator_cchar_delete(it);
if (it) bctbx_iterator_cchar_delete(it);
if (end) bctbx_iterator_cchar_delete(end);
}
iterator = bctbx_list_next(iterator);
}
if (phone_numbers) bctbx_list_free(phone_numbers);
addresses = linphone_friend_get_addresses(lf);
iterator = (bctbx_list_t *)addresses;
@ -659,13 +671,16 @@ static LinphoneFriendListStatus _linphone_friend_list_remove_friend(LinphoneFrie
char *uri = linphone_address_as_string_uri_only(lfaddr);
if(uri) {
bctbx_iterator_t * it = bctbx_map_cchar_find_key(list->friends_map_uri, uri);
if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(list->friends_map_uri))){
bctbx_iterator_t * end = bctbx_map_cchar_end(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(list->friends_map_uri, it);
}
bctbx_iterator_cchar_delete(it);
if (it) bctbx_iterator_cchar_delete(it);
if (end) bctbx_iterator_cchar_delete(end);
ms_free(uri);
}
iterator = bctbx_list_next(iterator);
}
@ -760,40 +775,50 @@ void linphone_friend_list_synchronize_friends_from_server(LinphoneFriendList *li
}
LinphoneFriend * linphone_friend_list_find_friend_by_address(const LinphoneFriendList *list, const LinphoneAddress *address) {
LinphoneFriend *result = NULL;
char *uri = linphone_address_as_string_uri_only(address);
bctbx_iterator_t* it = bctbx_map_cchar_find_key(list->friends_map_uri, uri);
if (!bctbx_iterator_cchar_equals(it, bctbx_map_cchar_end(list->friends_map_uri))) {
bctbx_pair_t *pair = bctbx_iterator_cchar_get_pair(it);
result = (LinphoneFriend *)bctbx_pair_cchar_get_second(pair);
LinphoneAddress *clean_addr = linphone_address_clone(address);
LinphoneFriend *lf;
if (linphone_address_has_uri_param(clean_addr, "gr")) {
linphone_address_remove_uri_param(clean_addr, "gr");
}
bctbx_iterator_cchar_delete(it);
ms_free(uri);
return result;
char *uri = linphone_address_as_string_uri_only(clean_addr);
lf = linphone_friend_list_find_friend_by_uri(list, uri);
bctbx_free(uri);
linphone_address_unref(clean_addr);
return lf;
}
LinphoneFriend * linphone_friend_list_find_friend_by_uri(const LinphoneFriendList *list, const char *uri) {
LinphoneFriend *result = NULL;
LinphoneAddress *address = linphone_address_new(uri);
if(address) {
result = linphone_friend_list_find_friend_by_address(list, address);
linphone_address_unref(address);
bctbx_iterator_t *it = bctbx_map_cchar_find_key(list->friends_map_uri, uri);
bctbx_iterator_t *end = bctbx_map_cchar_end(list->friends_map_uri);
if (!bctbx_iterator_cchar_equals(it, end)) {
bctbx_pair_t *pair = bctbx_iterator_cchar_get_pair(it);
result = (LinphoneFriend *)bctbx_pair_cchar_get_second(pair);
}
bctbx_iterator_cchar_delete(end);
bctbx_iterator_cchar_delete(it);
return result;
}
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);
result = (LinphoneFriend *)bctbx_pair_cchar_get_second(pair);
}
bctbx_iterator_cchar_delete(end);
bctbx_iterator_cchar_delete(it);
}
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))) {
bctbx_pair_t *pair = bctbx_iterator_cchar_get_pair(it);
return (LinphoneFriend *)bctbx_pair_cchar_get_second(pair);
}
}
return NULL;
}
LinphoneFriend * linphone_friend_list_find_friend_by_inc_subscribe(const LinphoneFriendList *list, SalOp *op) {
LinphoneFriend * linphone_friend_list_find_friend_by_inc_subscribe (
const LinphoneFriendList *list,
LinphonePrivate::SalOp *op
) {
const bctbx_list_t *elem;
for (elem = list->friends; elem != NULL; elem = bctbx_list_next(elem)) {
LinphoneFriend *lf = (LinphoneFriend *)bctbx_list_get_data(elem);
@ -802,11 +827,14 @@ LinphoneFriend * linphone_friend_list_find_friend_by_inc_subscribe(const Linphon
return NULL;
}
LinphoneFriend * linphone_friend_list_find_friend_by_out_subscribe(const LinphoneFriendList *list, SalOp *op) {
LinphoneFriend * linphone_friend_list_find_friend_by_out_subscribe (
const LinphoneFriendList *list,
LinphonePrivate::SalOp *op
) {
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) || sal_op_is_forked_of(lf->outsub, op))) return lf;
if (lf->outsub && ((lf->outsub == op) || lf->outsub->isForkedOf(op))) return lf;
}
return NULL;
}
@ -874,14 +902,14 @@ void linphone_friend_list_update_subscriptions(LinphoneFriendList *list){
const LinphoneAddress *address = _linphone_friend_list_get_rls_address(list);
bool_t only_when_registered = FALSE;
bool_t should_send_list_subscribe = FALSE;
if (list->lc){
if (address)
cfg = linphone_core_lookup_known_proxy(list->lc, address);
only_when_registered = linphone_core_should_subscribe_friends_only_when_registered(list->lc);
should_send_list_subscribe = (!only_when_registered || !cfg || cfg->state == LinphoneRegistrationOk);
}
if (address != NULL) {
if (list->enable_subscriptions) {
if (should_send_list_subscribe){
@ -939,7 +967,7 @@ void linphone_friend_list_notify_presence_received(LinphoneFriendList *list, Lin
const char *subtype = linphone_content_get_subtype(body);
if ((strcmp(type, "multipart") != 0) || (strcmp(subtype, "related") != 0)) {
ms_warning("multipart presence notified but it is not 'multipart/related'");
ms_warning("multipart presence notified but it is not 'multipart/related', instead is '%s/%s'", type, subtype);
return;
}
@ -1008,7 +1036,7 @@ LinphoneCore* linphone_friend_list_get_core(const LinphoneFriendList *list) {
static LinphoneStatus linphone_friend_list_import_friends_from_vcard4(LinphoneFriendList *list, bctbx_list_t *vcards) {
bctbx_list_t *vcards_iterator = NULL;
int count = 0;
if (!linphone_core_vcard_supported()) {
ms_error("vCard support wasn't enabled at compilation time");
return -1;
@ -1017,9 +1045,9 @@ static LinphoneStatus linphone_friend_list_import_friends_from_vcard4(LinphoneFr
ms_error("Can't import into a NULL list");
return -1;
}
vcards_iterator = vcards;
while (vcards_iterator != NULL && bctbx_list_get_data(vcards_iterator) != NULL) {
LinphoneVcard *vcard = (LinphoneVcard *)bctbx_list_get_data(vcards_iterator);
LinphoneFriend *lf = linphone_friend_new_from_vcard(vcard);
@ -1036,7 +1064,7 @@ static LinphoneStatus linphone_friend_list_import_friends_from_vcard4(LinphoneFr
bctbx_list_free(vcards);
linphone_core_store_friends_list_in_db(list->lc, list);
return count;
}
LinphoneStatus linphone_friend_list_import_friends_from_vcard4_file(LinphoneFriendList *list, const char *vcard_file) {
bctbx_list_t *vcards = NULL;
@ -1115,7 +1143,7 @@ void linphone_friend_list_enable_subscriptions(LinphoneFriendList *list, bool_t
} else {
linphone_friend_list_close_subscriptions(list);
}
}
}

View file

@ -1,8 +1,8 @@
############################################################################
################################################################################
# CMakeLists.txt
# Copyright (C) 2017 Belledonne Communications, Grenoble France
#
############################################################################
################################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -18,37 +18,39 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
############################################################################
################################################################################
if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER)
find_package(Doxygen)
if(DOXYGEN_FOUND)
if(DOXYGEN_DOT_FOUND)
set(top_srcdir "${PROJECT_SOURCE_DIR}")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
set(DOC_INPUT_FILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
${CMAKE_CURRENT_SOURCE_DIR}/doxygen.dox
${LINPHONE_HEADER_FILES}
)
set(XML_DIR "${CMAKE_CURRENT_BINARY_DIR}/xml")
set(LINPHONE_DOXYGEN_XML_DIR ${XML_DIR} PARENT_SCOPE)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${XML_DIR}/index.xml"
COMMAND ${CMAKE_COMMAND} -E remove -f html/* xml/*
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
DEPENDS ${DOC_INPUT_FILES}
)
add_custom_target(linphone-doc ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/html/index.html" "${XML_DIR}/index.xml")
if(ENABLE_DOC)
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html" "${XML_DIR}"
DESTINATION "${CMAKE_INSTALL_DATADIR}/doc/linphone-${LINPHONE_VERSION}"
)
endif()
else()
if (ENABLE_CXX_WRAPPER)
message(FATAL_ERROR "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.")
else()
message(WARNING "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.")
endif()
endif()
if (ENABLE_DOC OR ENABLE_CXX_WRAPPER OR ENABLE_CSHARP_WRAPPER OR ENABLE_JAVA_WRAPPER)
find_package(Doxygen)
if(DOXYGEN_FOUND)
if(DOXYGEN_DOT_FOUND)
set(top_srcdir "${PROJECT_SOURCE_DIR}")
set(DOXYGEN_INPUT "")
foreach (HEADER_FILE ${LINPHONE_HEADER_FILES})
string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${HEADER_FILE}\"")
endforeach ()
string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${CMAKE_CURRENT_SOURCE_DIR}\"")
string(CONCAT DOXYGEN_INPUT ${DOXYGEN_INPUT} " \"${PROJECT_SOURCE_DIR}/coreapi/help/examples/C\"")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
set(DOC_INPUT_FILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
${CMAKE_CURRENT_SOURCE_DIR}/doxygen.dox
${LINPHONE_HEADER_FILES}
)
set(XML_DIR "${CMAKE_CURRENT_BINARY_DIR}/xml")
set(LINPHONE_DOXYGEN_XML_DIR ${XML_DIR} PARENT_SCOPE)
add_custom_command(OUTPUT "${XML_DIR}/index.xml"
COMMAND ${CMAKE_COMMAND} -E remove -f xml/*
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
DEPENDS ${DOC_INPUT_FILES}
)
add_custom_target(linphone-doc ALL DEPENDS "${XML_DIR}/index.xml")
else()
if (ENABLE_CXX_WRAPPER)
message(FATAL_ERROR "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.")
else()
message(WARNING "The dot program is needed to generate the linphone documentation. You can get it from http://www.graphviz.org/.")
endif()
endif()
endif()
endif()

View file

@ -772,9 +772,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = @top_srcdir@/include/linphone \
@top_srcdir@/coreapi/help/doc/doxygen \
@top_srcdir@/coreapi/help/examples/C
INPUT = @DOXYGEN_INPUT@
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -1047,7 +1045,7 @@ IGNORE_PREFIX =
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = YES
GENERATE_HTML = NO
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@ -1591,7 +1589,7 @@ EXTRA_SEARCH_MAPPINGS =
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = YES
GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@ -1827,7 +1825,7 @@ RTF_SOURCE_CODE = NO
# classes and files.
# The default value is: NO.
GENERATE_MAN = YES
GENERATE_MAN = NO
# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@ -2006,7 +2004,8 @@ SEARCH_INCLUDES = YES
# preprocessor.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH = .
INCLUDE_PATH = . \
@LINPHONE_HEADER_ROOT_DIR@
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the

View file

@ -20,42 +20,40 @@
#
############################################################################
if (ENABLE_SPHINX_DOC)
set(GENERATED_LANGUAGES c cpp csharp)
set(DOCUMENTATION_DIRS )
set(GENERATED_SPHINX_SOURCES )
foreach(LANGUAGE_ ${GENERATED_LANGUAGES})
set(DOCUMENTATION_DIR ${CMAKE_CURRENT_BINARY_DIR}/source/${LANGUAGE_})
list(APPEND DOCUMENTATION_DIRS ${DOCUMENTATION_DIR})
list(APPEND GENERATED_SPHINX_SOURCES ${DOCUMENTATION_DIR}/index.rst)
endforeach(LANGUAGE_)
set(PYTHON_SCRIPTS gendoc.py
${linphone_SOURCE_DIR}/tools/abstractapi.py
${linphone_SOURCE_DIR}/tools/genapixml.py
${linphone_SOURCE_DIR}/tools/metadoc.py
${linphone_SOURCE_DIR}/tools/metaname.py
if (ENABLE_DOC)
set(doc_source_dir ${CMAKE_CURRENT_BINARY_DIR}/source)
set(doc_output_dir ${CMAKE_CURRENT_BINARY_DIR}/build)
set(reference_doc_source_dir ${doc_source_dir}/reference)
set(static_documentation_files
guides/authentication.rst
guides/buddy_list.rst
guides/call_control.rst
guides/call_logs.rst
guides/call_misc.rst
guides/chatroom.rst
guides/conferencing.rst
guides/event_api.rst
guides/initializing.rst
guides/ios_portability.rst
guides/linphone_address.rst
guides/media_parameters.rst
guides/misc.rst
guides/network_parameters.rst
guides/proxies.rst
index.rst
logo.png
samples/samples.rst
)
set(MUSTACHE_TEMPLATES class_page.mustache
enums_page.mustache
index_page.mustache
)
configure_file(conf.py.in source/conf.py)
configure_file(source/index.rst source/index.rst COPYONLY)
add_custom_command(OUTPUT ${GENERATED_SPHINX_SOURCES}
COMMAND ${CMAKE_COMMAND} -E remove -f ${DOCUMENTATION_DIRS}
COMMAND ${PYTHON_EXECUTABLE} '${CMAKE_CURRENT_SOURCE_DIR}/gendoc.py' '${LINPHONE_DOXYGEN_XML_DIR}' -o 'source'
DEPENDS ${PYTHON_SCRIPTS}
${MUSTACHE_TEMPLATES}
${LINPHONE_DOXYGEN_XML_DIR}/index.xml
linphone-doc
)
add_custom_command(OUTPUT build/html/index.html
COMMAND ${CMAKE_COMMAND} -E remove_directory build
COMMAND ${PYTHON_EXECUTABLE} -msphinx -M html 'source' 'build'
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/source/conf.py
${CMAKE_CURRENT_BINARY_DIR}/source/index.rst
${GENERATED_SPHINX_SOURCES}
)
add_custom_target(sphinx-doc ALL DEPENDS build/html/index.html)
configure_file(conf.py.in ${doc_source_dir}/conf.py)
foreach(file ${static_documentation_files})
configure_file(${file} ${doc_source_dir}/${file} COPYONLY)
endforeach(file)
foreach(source ${LINPHONE_C_EXAMPLES_SOURCE})
configure_file(${source} ${doc_source_dir}/samples/ COPYONLY)
endforeach(source)
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${doc_source_dir}/_static ${reference_doc_source_dir})
add_custom_target(sphinx-doc ALL ${PYTHON_EXECUTABLE} '${CMAKE_CURRENT_SOURCE_DIR}/gendoc.py' '${LINPHONE_DOXYGEN_XML_DIR}' -o '${reference_doc_source_dir}'
COMMAND ${PYTHON_EXECUTABLE} -msphinx -M html '${doc_source_dir}' '${doc_output_dir}'
DEPENDS linphone-doc)
install(DIRECTORY ${doc_output_dir}/html/ DESTINATION ${CMAKE_INSTALL_DOCDIR}/${LINPHONE_VERSION})
endif()

View file

@ -1,6 +1,13 @@
{{#hasNamespaceDeclarator}}
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{namespace}}}
{{#isJava}}
:noindex:
{{/isJava}}
{{/hasNamespaceDeclarator}}
{{#make_chapter}}{{{className}}} class{{/make_chapter}}
.. {{#write_declarator}}class{{/write_declarator}}:: {{{fullClassName}}}
.. {{#write_declarator}}class{{/write_declarator}}:: {{{classDeclaration}}}
{{#briefDoc}}
{{#lines}}
@ -17,9 +24,24 @@
{{{selector}}}
{{#hasNamespaceDeclarator}}
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}}
{{#isJava}}
:noindex:
{{/isJava}}
{{/hasNamespaceDeclarator}}
Summary
=======
{{#hasEnums}}
Enums
-----
{{{enumsSummary}}}
{{/hasEnums}}
{{#hasProperties}}
Properties
----------
@ -41,18 +63,61 @@ Class methods
{{{classMethodsSummary}}}
{{/hasClassMethods}}
Detailed descriptions
=====================
{{#hasEnums}}
Enums
-----
{{#enums}}
{{#make_subsection}}{{{name}}}{{/make_subsection}}
.. {{#write_declarator}}enum{{/write_declarator}}:: {{{declaration}}}
{{#briefDesc}}
{{#lines}}
{{{line}}}
{{/lines}}
{{/briefDesc}}
{{{selector}}}
{{#enumerators}}
{{#isNotJava}}
.. {{#write_declarator}}enumerator{{/write_declarator}}:: {{{name}}}
{{/isNotJava}}
{{#isJava}}
**{{{name}}}**
{{/isJava}}
{{#briefDesc}}
{{#lines}}
{{{line}}}
{{/lines}}
{{/briefDesc}}
{{{selector}}}
{{/enumerators}}
{{/enums}}
{{/hasEnums}}
{{#hasProperties}}
Properties
----------
{{#properties}}
.. _{{{ref_label}}}:
{{{title}}}
{{#hasNamespaceDeclarator}}
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}}
{{#isJava}}
:noindex:
{{/isJava}}
{{/hasNamespaceDeclarator}}
{{#getter}}
@ -100,6 +165,9 @@ Public methods
{{#hasNamespaceDeclarator}}
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}}
{{#isJava}}
:noindex:
{{/isJava}}
{{/hasNamespaceDeclarator}}
{{#methods}}
@ -128,6 +196,9 @@ Class methods
{{#hasNamespaceDeclarator}}
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{fullClassName}}}
{{#isJava}}
:noindex:
{{/isJava}}
{{/hasNamespaceDeclarator}}
{{#classMethods}}

View file

@ -31,7 +31,7 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx_csharp.csharp']
extensions = ['sphinx_csharp.csharp', 'javasphinx']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@ -83,20 +83,33 @@ todo_include_todos = False
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
#html_theme = 'alabaster'
html_theme = 'classic'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
html_theme_options = {
'sidebarwidth': '360',
'body_max_width': '100%',
'collapsiblesidebar': 'true'
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Path to the picture to use as logo.
html_logo = 'logo.png'
# Enable html5
html_experimental_html5_writer = True
# Side bar customization
#html_sidebars = {
# 'reference/*/*' : ['searchbox.html', 'globaltoc.html']
#}
# -- Options for HTMLHelp output ------------------------------------------

View file

@ -0,0 +1,39 @@
{{#namespace}}
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{namespace}}}
{{#isJava}}
:noindex:
{{/isJava}}
{{/namespace}}
{{#enum}}
{{#make_chapter}}{{{name}}} enum{{/make_chapter}}
.. {{#write_declarator}}enum{{/write_declarator}}:: {{{declaration}}}
{{#briefDesc}}
{{#lines}}
{{{line}}}
{{/lines}}
{{/briefDesc}}
{{{selector}}}
{{#enumerators}}
{{#isNotJava}}
.. {{#write_declarator}}enumerator{{/write_declarator}}:: {{{name}}}
{{/isNotJava}}
{{#isJava}}
**{{{name}}}**
{{/isJava}}
{{#briefDesc}}
{{#lines}}
{{{line}}}
{{/lines}}
{{/briefDesc}}
{{{selector}}}
{{/enumerators}}
{{/enum}}

View file

@ -1,30 +0,0 @@
{{#enums}}
{{{sectionName}}}
.. {{#write_declarator}}enum{{/write_declarator}}:: {{{fullName}}}
{{#briefDesc}}
{{#lines}}
{{{line}}}
{{/lines}}
{{/briefDesc}}
{{{selector}}}
{{#hasNamespaceDeclarator}}
.. {{#write_declarator}}namespace{{/write_declarator}}:: {{{namespace}}}
{{/hasNamespaceDeclarator}}
{{#enumerators}}
.. {{#write_declarator}}enumerator{{/write_declarator}}:: {{{name}}}{{#value}} = {{{value}}}{{/value}}
{{#briefDesc}}
{{#lines}}
{{{line}}}
{{/lines}}
{{/briefDesc}}
{{{selector}}}
{{/enumerators}}
{{/enums}}

View file

@ -18,10 +18,12 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import sys
import os
import argparse
import hashlib
import logging
import os
import pystache
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', 'tools'))
import abstractapi
@ -30,7 +32,18 @@ import metaname
import metadoc
def md5sum(file):
hasher = hashlib.md5()
with open(file, mode='rb') as f:
hasher.update(f.read())
return hasher.hexdigest()
class RstTools:
@staticmethod
def make_part(text):
return RstTools.make_section(text, char='#', overline=True)
@staticmethod
def make_chapter(text):
return RstTools.make_section(text, char='*', overline=True)
@ -55,12 +68,27 @@ class RstTools:
class Table:
def __init__(self):
self._rows = []
self._widths = []
self._heights = []
@property
def rows(self):
return self._rows
class CSVTable(Table):
def addrow(self, row):
self._rows.append(', '.join([self._format_cell(cell) for cell in row]))
def __str__(self):
return '.. csv-table::\n\t\n\t' + '\n\t'.join(self._rows)
def _format_cell(self, cell):
return '"{0}"'.format(cell.replace('"', '""'))
class GridTable(Table):
def __init__(self):
RstTools.Table.__init__(self)
self._widths = []
self._heights = []
def addrow(self, row):
if len(self._widths) == 0:
@ -124,78 +152,132 @@ class RstTools:
class LangInfo:
def __init__(self, langCode):
if langCode not in LangInfo._displayNames:
raise ValueError("Invalid language code '{0}'".format(langCode))
self.langCode = langCode
self.displayName = LangInfo._lang_code_to_display_name(langCode)
self.nameTranslator = metaname.Translator.get(langCode)
self.langTranslator = abstractapi.Translator.get(langCode)
self.docTranslator = metadoc.SphinxTranslator(langCode)
@staticmethod
def _lang_code_to_display_name(langCode):
if langCode == 'C':
return 'C'
elif langCode == 'Cpp':
return 'C++'
elif langCode == 'CSharp':
return 'C#'
else:
raise ValueError("Invalid language code: '{0}'".format(langCode))
@property
def displayName(self):
return LangInfo._displayNames[self.langCode]
@property
def directory(self):
return self.langCode.lower()
_displayNames = {
'C' : 'C',
'Cpp' : 'C++',
'Java' : 'Java',
'CSharp': 'C#'
}
class SphinxPage(object):
def __init__(self, lang, langs, filename):
class SphinxPart(object):
def __init__(self, lang, langs):
object.__init__(self)
self.lang = lang
self.langs = langs
self.filename = filename
@property
def hasNamespaceDeclarator(self):
return ('namespaceDeclarator' in dir(self.docTranslator))
@property
def language(self):
return self.lang.displayName
@property
def docTranslator(self):
return self.lang.docTranslator
@property
def hasNamespaceDeclarator(self):
return ('namespaceDeclarator' in dir(self.docTranslator))
@property
def isJava(self):
return self.lang.langCode == 'Java'
@property
def isNotJava(self):
return not self.isJava
def make_part(self):
return lambda text: RstTools.make_part(pystache.render(text, self))
def make_chapter(self):
return lambda text: RstTools.make_chapter(pystache.render(text, self))
def make_section(self):
return lambda text: RstTools.make_section(pystache.render(text, self))
def make_subsection(self):
return lambda text: RstTools.make_subsection(pystache.render(text, self.properties))
return lambda text: RstTools.make_subsection(pystache.render(text, self))
def make_subsection(self):
return lambda text: RstTools.make_subsubsection(pystache.render(text, self))
def write_declarator(self):
return lambda text: self.docTranslator.get_declarator(text)
def write(self, directory):
r = pystache.Renderer()
filepath = os.path.join(directory, self.filename)
with open(filepath, mode='w') as f:
f.write(r.render(self))
def _get_translated_namespace(self, obj):
namespace = obj.find_first_ancestor_by_type(abstractapi.Namespace)
return namespace.name.translate(self.lang.nameTranslator, recursive=True)
def _make_selector(self, obj):
links = []
ref = metadoc.Reference(None)
ref.relatedObject = obj
for lang in self.langs:
if lang is self.lang:
link = lang.displayName
else:
if lang.langCode == 'Java' and type(obj) is abstractapi.Enumerator:
ref = metadoc.Reference.make_ref_from_object(None, obj.parent)
else:
ref = metadoc.Reference.make_ref_from_object(None, obj)
link = ref.translate(lang.docTranslator, label=lang.displayName)
links.append(link)
return ' '.join(links)
class EnumPart(SphinxPart):
def __init__(self, enum, lang, langs, namespace=None):
SphinxPart.__init__(self, lang, langs)
self.name = enum.name.translate(self.lang.nameTranslator)
self.fullName = enum.name.translate(self.lang.nameTranslator, recursive=True)
self.briefDesc = enum.briefDescription.translate(self.docTranslator)
self.enumerators = [self._translate_enumerator(enumerator) for enumerator in enum.enumerators]
self.selector = self._make_selector(enum)
self.sectionName = RstTools.make_section(self.name)
self.declaration = 'public enum {0}'.format(self.name) if self.lang.langCode == 'Java' else self.name
ref = metadoc.ClassReference(None)
ref.relatedObject = enum
self.link = ref.translate(lang.docTranslator)
def _translate_enumerator(self, enumerator):
return {
'name' : enumerator.name.translate(self.lang.nameTranslator),
'briefDesc' : enumerator.briefDescription.translate(self.docTranslator),
'value' : enumerator.translate_value(self.lang.langTranslator),
'selector' : self._make_selector(enumerator)
}
class SphinxPage(SphinxPart):
def __init__(self, lang, langs, filename):
SphinxPart.__init__(self, lang, langs)
self.filename = filename
def write(self, directory):
r = pystache.Renderer()
filepath = os.path.join(directory, self.filename)
tmpFilepath = filepath + '.tmp'
with open(tmpFilepath, mode='w') as f:
f.write(r.render(self))
if os.path.exists(filepath) and md5sum(filepath) == md5sum(tmpFilepath):
os.remove(tmpFilepath)
else:
os.rename(tmpFilepath, filepath)
return filepath
def _get_translated_namespace(self, obj):
namespace = obj.find_first_ancestor_by_type(abstractapi.Namespace)
return namespace.name.translate(self.lang.nameTranslator, recursive=True)
@staticmethod
def _classname_to_filename(classname):
@ -203,60 +285,59 @@ class SphinxPage(object):
class IndexPage(SphinxPage):
def __init__(self, lang, langs):
SphinxPage.__init__(self, lang, langs, 'index.rst')
self.tocEntries = []
def add_class_entry(self, _class):
self.tocEntries.append({'entryName': SphinxPage._classname_to_filename(_class.name)})
def __init__(self, lang, filename):
SphinxPage.__init__(self, lang, None, filename)
self._entries = []
self._sorted = True
@property
def title(self):
return RstTools.make_chapter("{0} API".format(self.lang.displayName))
@property
def dir(self):
return self.lang.directory
@property
def entries(self):
if not self._sorted:
self._entries.sort(key=lambda x: x['filename'])
self._sorted = True
return self._entries
def add_entry(self, filename):
self.entries.append({'filename': filename})
self._sorted = False
class EnumsPage(SphinxPage):
def __init__(self, lang, langs, enums):
SphinxPage.__init__(self, lang, langs, 'enums.rst')
self._translate_enums(enums)
def _translate_enums(self, enums):
self.enums = []
for enum in enums:
translatedEnum = {
'name' : enum.name.translate(self.lang.nameTranslator),
'fullName' : enum.name.translate(self.lang.nameTranslator, recursive=True),
'briefDesc' : enum.briefDescription.translate(self.docTranslator),
'enumerators' : self._translate_enum_values(enum),
'selector' : self._make_selector(enum)
}
translatedEnum['namespace'] = self._get_translated_namespace(enum) if self.lang.langCode == 'Cpp' else translatedEnum['fullName']
translatedEnum['sectionName'] = RstTools.make_section(translatedEnum['name'])
self.enums.append(translatedEnum)
def _translate_enum_values(self, enum):
translatedEnumerators = []
for enumerator in enum.enumerators:
translatedValue = {
'name' : enumerator.name.translate(self.lang.nameTranslator),
'briefDesc' : enumerator.briefDescription.translate(self.docTranslator),
'value' : enumerator.translate_value(self.lang.langTranslator),
'selector' : self._make_selector(enumerator)
}
translatedEnumerators.append(translatedValue)
return translatedEnumerators
class EnumPage(SphinxPage):
def __init__(self, enum, lang, langs):
filename = SphinxPage._classname_to_filename(enum.name)
SphinxPage.__init__(self, lang, langs, filename)
namespace = enum.find_first_ancestor_by_type(abstractapi.Namespace)
self.namespace = namespace.name.translate(lang.nameTranslator) if lang.langCode != 'C' else None
self.enum = EnumPart(enum, lang, langs, namespace=namespace)
class ClassPage(SphinxPage):
def __init__(self, _class, lang, langs):
filename = SphinxPage._classname_to_filename(_class.name)
SphinxPage.__init__(self, lang, langs, filename)
self.namespace = self._get_translated_namespace(_class)
namespace = _class.find_first_ancestor_by_type(abstractapi.Namespace)
self.namespace = namespace.name.translate(self.lang.nameTranslator, recursive=True)
self.className = _class.name.translate(self.lang.nameTranslator)
self.fullClassName = _class.name.translate(self.lang.nameTranslator, recursive=True)
self.briefDoc = _class.briefDescription.translate(self.docTranslator)
self.detailedDoc = _class.detailedDescription.translate(self.docTranslator) if _class.detailedDescription is not None else None
self.properties = self._translate_properties(_class.properties)
self.enums = [EnumPart(enum, lang, langs) for enum in _class.enums]
self.properties = self._translate_properties(_class.properties) if isinstance(_class, abstractapi.Class) else []
self.methods = self._translate_methods(_class.instanceMethods)
self.classMethods = self._translate_methods(_class.classMethods)
self.selector = self._make_selector(_class)
@property
def classDeclaration(self):
return 'public interface {0}'.format(self.className) if self.lang.langCode == 'Java' else self.className
@property
def hasMethods(self):
@ -269,17 +350,22 @@ class ClassPage(SphinxPage):
@property
def hasProperties(self):
return len(self.properties) > 0
@property
def hasEnums(self):
return len(self.enums) > 0
def _translate_properties(self, properties):
translatedProperties = []
for property_ in properties:
propertyAttr = {
'name' : property_.name.translate(self.lang.nameTranslator),
'ref_label' : '{0}_{1}'.format(self.lang.langCode, property_.name.to_snake_case(fullName=True)),
'getter' : self._translate_method(property_.getter) if property_.getter is not None else None,
'setter' : self._translate_method(property_.setter) if property_.setter is not None else None
}
propertyAttr['title'] = RstTools.make_subsubsection(propertyAttr['name'])
propertyAttr['ref_label'] = (self.lang.langCode + '_')
propertyAttr['ref_label'] += (property_.getter.name.to_snake_case(fullName=True) if property_.getter is not None else property_.setter.name.to_snake_case(fullName=True))
translatedProperties.append(propertyAttr)
return translatedProperties
@ -290,80 +376,113 @@ class ClassPage(SphinxPage):
return translatedMethods
def _translate_method(self, method):
prototypeParams = {}
if self.lang.langCode == 'Cpp':
prototypeParams['showStdNs'] = True
namespace = method.find_first_ancestor_by_type(abstractapi.Class,abstractapi.Interface)
methAttr = {
'prototype' : method.translate_as_prototype(self.lang.langTranslator, **prototypeParams),
'prototype' : method.translate_as_prototype(self.lang.langTranslator, namespace=namespace),
'briefDoc' : method.briefDescription.translate(self.docTranslator),
'detailedDoc' : method.detailedDescription.translate(self.docTranslator),
'selector' : self._make_selector(method)
}
reference = metadoc.FunctionReference(None)
reference.relatedObject = method
methAttr['link'] = reference.translate(self.lang.docTranslator)
methAttr['link'] = reference.translate(self.lang.docTranslator, namespace=method.find_first_ancestor_by_type(abstractapi.Class, abstractapi.Interface))
return methAttr
@property
def enumsSummary(self):
table = RstTools.CSVTable()
for enum in self.enums:
briefDoc = ' '.join([line['line'] for line in enum.briefDesc['lines']])
table.addrow((enum.link, briefDoc))
return table
@property
def propertiesSummary(self):
table = RstTools.Table()
table = RstTools.CSVTable()
for property_ in self.properties:
reference = ':ref:`{0}`'.format(property_['ref_label'])
briefDoc = property_['getter']['briefDoc'] if property_['getter'] is not None else property_['setter']['briefDoc']
briefDoc = '\n'.join([line['line'] for line in briefDoc['lines']])
briefDoc = ' '.join([line['line'] for line in briefDoc['lines']])
table.addrow([reference, briefDoc])
return table
@property
def instanceMethodsSummary(self):
table = RstTools.Table()
table = RstTools.CSVTable()
for method in self.methods:
briefDoc = '\n'.join([line['line'] for line in method['briefDoc']['lines']])
briefDoc = ' '.join([line['line'] for line in method['briefDoc']['lines']])
table.addrow([method['link'], briefDoc])
return table
@property
def classMethodsSummary(self):
table = RstTools.Table()
table = RstTools.CSVTable()
for method in self.classMethods:
briefDoc = '\n'.join([line['line'] for line in method['briefDoc']['lines']])
briefDoc = ' '.join([line['line'] for line in method['briefDoc']['lines']])
table.addrow([method['link'], briefDoc])
return table
class OldFilesCleaner:
def __init__(self, rootDirectory):
self._filesToKeep = set()
self.root = rootDirectory
def protect_file(self, directory):
self._filesToKeep.add(directory)
def clean(self):
self._clean(self.root)
def _clean(self, dir_):
if os.path.isdir(dir_):
for filename in os.listdir(dir_):
self._clean(os.path.join(dir_, filename))
elif dir_ not in self._filesToKeep:
os.remove(dir_)
class DocGenerator:
def __init__(self, api):
self.api = api
self.languages = [
LangInfo('C'),
LangInfo('Cpp'),
LangInfo('Java'),
LangInfo('CSharp')
]
def generate(self, outputdir):
for lang in self.languages:
subdirectory = lang.langCode.lower()
directory = os.path.join(args.outputdir, subdirectory)
directory = os.path.join(args.outputdir, lang.directory)
cleaner = OldFilesCleaner(directory)
indexPage = IndexPage(lang, 'index.rst')
if not os.path.exists(directory):
os.mkdir(directory)
enumsPage = EnumsPage(lang, self.languages, absApiParser.enums)
enumsPage.write(directory)
indexPage = IndexPage(lang, self.languages)
for _class in absApiParser.classes:
page = ClassPage(_class, lang, self.languages)
page.write(directory)
indexPage.add_class_entry(_class)
indexPage.write(directory)
for enum in self.api.namespace.enums:
page = EnumPage(enum, lang, self.languages)
filepath = page.write(directory)
indexPage.add_entry(page.filename)
cleaner.protect_file(filepath)
for class_ in (self.api.namespace.classes + self.api.namespace.interfaces):
page = ClassPage(class_, lang, self.languages)
filepath = page.write(directory)
indexPage.add_entry(page.filename)
cleaner.protect_file(filepath)
filepath = indexPage.write(directory)
cleaner.protect_file(filepath)
cleaner.clean()
if __name__ == '__main__':
argparser = argparse.ArgumentParser(description='Generate a sphinx project to generate the documentation of Linphone Core API.')
argparser.add_argument('xmldir', type=str, help='directory holding the XML documentation of the C API generated by Doxygen')
argparser.add_argument('-o --output', type=str, help='directory into where Sphinx source files will be written', dest='outputdir', default='.')
argparser.add_argument('-v --verbose', action='store_true', default=False, dest='verbose_mode', help='Show warning and info messages')
args = argparser.parse_args()
loglevel = logging.INFO if args.verbose_mode else logging.ERROR
logging.basicConfig(format='%(levelname)s[%(name)s]: %(message)s', level=loglevel)
cProject = capi.Project()
cProject.initFromDir(args.xmldir)

View file

@ -0,0 +1,4 @@
Managing authentication: userid and passwords
=============================================

View file

@ -0,0 +1,57 @@
Managing Buddies and buddy list and presence
============================================
Buddies and buddy list
----------------------
Each buddy is represented by a :cpp:type:`LinphoneFriend` object created by function :cpp:func:`linphone_friend_new`.
Buddy configuration parameters like :cpp:func:`sip uri <linphone_friend_set_addr>` or :cpp:func:`status publication <linphone_friend_set_inc_subscribe_policy>` policy for
this :cpp:type:`friend <LinphoneFriend>` are configurable for each buddy.
Here under a typical buddy creation:
.. code-block:: c
LinphoneFriend* my_friend=linphone_friend_new_with_addr("sip:joe@sip.linphone.org"); /*creates friend object for buddy joe*/
linphone_friend_enable_subscribes(my_friend,TRUE); /*configure this friend to emit SUBSCRIBE message after being added to LinphoneCore*/
linphone_friend_set_inc_subscribe_policy(my_friend,LinphoneSPAccept); /* accept Incoming subscription request for this friend*/
:cpp:type:`Friends <LinphoneFriend>` status changes are reported by callback LinphoneCoreVTable.notify_presence_recv
.. code-block:: c
static void notify_presence_recv_updated (struct _LinphoneCore *lc, LinphoneFriend *friend) {
const LinphoneAddress* friend_address = linphone_friend_get_address(friend);
printf("New state state [%s] for user id [%s] \n"
,linphone_online_status_to_string(linphone_friend_get_status(friend))
,linphone_address_as_string (friend_address));
}
Once created a buddy can be added to the buddy list using function :cpp:func:`linphone_core_add_friend`. Added friends will be notified
about :cpp:func:`local status changes <linphone_core_set_presence_info>`.
Any subsequente modifications to :cpp:type:`LinphoneFriend` must be first started by a call to function :cpp:func:`linphone_friend_edit` and validated by function :cpp:func:`linphone_friend_done`.
.. code-block:: c
linphone_friend_edit(my_friend); /* start editing friend */
linphone_friend_enable_subscribes(my_friend,FALSE); /*disable subscription for this friend*/
linphone_friend_done(my_friend); /*commit changes triggering an UNSUBSCRIBE message*/
Publishing presence status
--------------------------
Local presence status can be changed using function :cpp:func:`linphone_core_set_presence_model`. New status is propagated to all
friends :cpp:func:`previously added <linphone_core_add_friend>` to :cpp:type:`LinphoneCore`.
Handling incoming subscription request
--------------------------------------
New incoming subscription requests are process according to :cpp:func:`the incoming subscription policy state <linphone_friend_set_inc_subscribe_policy>` for subscription
initiated by :cpp:func:`members of the buddy list <linphone_core_add_friend>`.
For incoming request comming from an unknown buddy, the call back LinphoneCoreVTable.new_subscription_request is invoked.
A complete tutorial can be found at : \ref buddy_tutorials "Registration tutorial"

View file

@ -0,0 +1,9 @@
Placing and receiving calls
===========================
The :cpp:type:`LinphoneCall` object represents an incoming or outgoing call managed by the :cpp:type:`LinphoneCore`.
Outgoing calls can be created using :cpp:func:`linphone_core_invite` or :cpp:func:`linphone_core_invite_address`, while incoming calls are notified to the application
through the LinphoneCoreVTable::call_state_changed callback.
.. seealso:: :ref:`"Basic Call" <basic_call_code_sample>` source code.

View file

@ -0,0 +1,2 @@
Managing call logs
==================

View file

@ -0,0 +1,4 @@
Obtaining information about a running call: sound volumes, quality indicators
=============================================================================
When a call is running, it is possible to retrieve in real time current measured volumes and quality indicator.

View file

@ -0,0 +1,28 @@
Chat room and messaging
=======================
Exchanging text messages
------------------------
Messages are sent using :cpp:type:`LinphoneChatRoom` object. First step is to create a :cpp:func:`chat room <linphone_core_get_chat_room>`
from a peer sip uri.
.. code-block:: c
LinphoneChatRoom* chat_room = linphone_core_get_chat_room(lc,"sip:joe@sip.linphone.org");
Once created, messages are sent using function :cpp:func:`linphone_chat_room_send_message`.
.. code-block:: c
linphone_chat_room_send_message(chat_room,"Hello world"); /*sending message*/
Incoming message are received from call back LinphoneCoreVTable.text_received
.. code-block:: c
void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message) {
printf(" Message [%s] received from [%s] \n",message,linphone_address_as_string (from));
}
.. seealso:: A complete tutorial can be found at :ref:`"Chatroom and messaging" <chatroom_code_sample>` source code.

View file

@ -0,0 +1,21 @@
Making an audio conference
==========================
This API allows to create a conference entirely managed by the client. No server capabilities are required.
The way such conference is created is by doing the following:
#. The application shall makes "normal" calls to several destinations (using :cpp:func:`linphone_core_invite`), one after another.
#. While initiating the second call, the first one is automatically paused.
#. Then, once the second call is established, the application has the possibility to merge the two calls to form a conference where each participant
(the local participant, the remote destination of the first call, the remote destination of the second call) can talk together.
This must be done by adding the two calls to the conference using :cpp:func:`linphone_core_add_to_conference`.
Once merged into a conference the :cpp:type:`LinphoneCall` objects representing the calls that were established remain unchanged, except that
they are tagged as part of the conference (see :cpp:func:`linphone_call_is_in_conference`). The calls in a conference are in the :cpp:enumerator:`LinphoneCallStreamsRunning` state.
Only a single conference can be created: the purpose of this feature is to allow the local user to create, take part and manage the conference.
This API is not designed to create a conference server application.
Up to 10 calls can be merged into the conference, however depending on the CPU usage required for doing the encoding/decoding of the streams of each participants,
the effective limit can be lower.

View file

@ -0,0 +1,4 @@
Managing generic subscriptions and publishes
============================================
The :cpp:type:`LinphoneEvent` api allows application to control subscriptions, receive notifications and make publish to peers, in a generic manner.

View file

@ -0,0 +1,4 @@
Initializing liblinphone
========================

View file

@ -0,0 +1,285 @@
iOS portability
===============
Multitasking
------------
Liblinphone for IOS natively supports multitasking assuming application follows multitasking guides provided by Apple.
First step is to declare application as multitasked. It means adding background mode for both audio and voip to Info.plist file.
.. code-block:: xml
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
<string>audio</string>
</array>
SIP socket
^^^^^^^^^^
Recommended mode is SIP over TCP, because UDP usually requires frequent keep alives for maintaining NAT association at the IP router level. This can
be as frequent as one UDP packet every 15 seconds to maintain the NAT association accross NAT routers. Doing such drains the battery very fast, and
furthermore the iOS keep-alive designed by Apple to handle this task can only be called with a minimum of 10 minutes interval.
For TCP, liblinphone automatically configures SIP socket for voip (I.E kCFStreamNetworkServiceType set to kCFStreamNetworkServiceTypeVoIP).
.. note::
Since IOS > 4.1 Apple disabled voip mode for UDP sockets.
Entering background mode
^^^^^^^^^^^^^^^^^^^^^^^^
Before entering in background mode (through ``- (void)applicationDidEnterBackground:(UIApplication *)application``), the application must first refresh
sip registration using function :cpp:func:`linphone_core_refresh_registers` and register a keep-alive handler for periodically refreshing the registration.
The speudo code below shows how to register a keep alive handler:
.. code-block:: objective-c
//First refresh registration
linphone_core_refresh_registers(theLinphoneCore);
//wait for registration answer
int i=0;
while (!linphone_proxy_config_is_registered(proxyCfg) && i++<40 ) {
linphone_core_iterate(theLinphoneCore);
usleep(100000);
}
//register keepalive handler
[[UIApplication sharedApplication] setKeepAliveTimeout:600/*minimal interval is 600 s*/
handler:^{
//refresh sip registration
linphone_core_refresh_registers(theLinphoneCore);
//make sure sip REGISTER is sent
linphone_core_iterate(theLinphoneCore);
}];
Incoming call notification while in background mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Assuming application using liblinphone is well configured for multitasking, incoming calls arriving while liblinphone is in background mode will simply wakeup
liblinphone thread but not resume GUI. To wakeup GUI, it is recommended to send a Local Notification to the user from the #LinphoneCoreCallStateChangedCb. Here
under a speudo code for this operation:
.. code-block:: objective-c
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
// Create a new notification
UILocalNotification* notif = [[[UILocalNotification alloc] init] autorelease];
if (notif) {
notif.repeatInterval = 0;
notif.alertBody =@"New incoming call";
notif.alertAction = @"Answer";
notif.soundName = @"oldphone-mono-30s.caf";
[[UIApplication sharedApplication] presentLocalNotificationNow:notif];
}
Networking
----------
WWAN connection
^^^^^^^^^^^^^^^
Liblinphone relies on iOS's standard BSD socket layer for sip/rtp networking. On IOS, WWAN connection is supposed to automatically bring up on any networking
resquest issued by an application. At least on iPhone OS 3.x, BSD sockets do not implement this behavior. So it is recomended to add a special code to make sure
the WWAN connection is properly setup. Pseudo code below describes a way to force WWAN connection by setting up a dummy TCP connection.
.. code-block:: objective-c
/*start a new thread to avoid blocking the main ui in case of peer host failure*/
[NSThread detachNewThreadSelector:@selector(runNetworkConnection) toTarget:self withObject:nil];
-(void) runNetworkConnection {
CFWriteStreamRef writeStream;
//create a dummy socket
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"192.168.0.200", 15000, nil, &writeStream);
CFWriteStreamOpen (writeStream);
const char* buff="hello";
//try to write on this socket
CFWriteStreamWrite (writeStream,(const UInt8*)buff,strlen(buff));
CFWriteStreamClose (writeStream);
}
It is recommanded to perform this task each time the application is woken up, including keep alive handler.
Managing IP connection state
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Liblinphone for IOS relies on the application to be informed of network connectivity changes. Network state changes when the IP connection moves from DOWN to UP,
or from WIFI to WWAN. Applications using liblinphone must inform libliblinphone of this changes using function :cpp:func:`linphone_core_set_network_reachable`.
Usually this method is called from the IOS NetworkReachability callback. Here under a sample code:
.. code-block:: c
//typical reachability callback
void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void * info) {
if ((flags == 0) | (flags & (kSCNetworkReachabilityFlagsConnectionRequired |kSCNetworkReachabilityFlagsConnectionOnTraffic))) {
//network state is off
linphone_core_set_network_reachable(lc,false);
((LinphoneManager*)info).connectivity = none;
} else {
Connectivity newConnectivity = flags & kSCNetworkReachabilityFlagsIsWWAN ? wwan:wifi;
if (lLinphoneMgr.connectivity == none) {
//notify new network state
linphone_core_set_network_reachable(lc,true);
} else if (lLinphoneMgr.connectivity != newConnectivity) {
// connectivity has changed
linphone_core_set_network_reachable(lc,false);
linphone_core_set_network_reachable(lc,true);
}
//store new connectivity status
lLinphoneMgr.connectivity=newConnectivity;
}
}
Sound cards
-----------
Since IOS 5.0, liblinphone supports 2 sound cards. *AU: Audio Unit Receiver* based on IO units for voice calls plus *AQ: Audio Queue Device* dedicated to rings.
Here under the recommended settings (I.E default one)
.. code-block:: c
linphone_core_set_playback_device(lc, "AU: Audio Unit Receiver");
linphone_core_set_ringer_device(lc, "AQ: Audio Queue Device");
linphone_core_set_capture_device(lc, "AU: Audio Unit Receiver");
GSM call interaction
--------------------
To ensure gentle interaction with GSM calls, it is recommended to register an AudioSession delegate. This allows the application to be notified when its audio
session is interrupted/resumed (presumably by a GSM call).
.. code-block:: objective-c
// declare a class handling the AVAudioSessionDelegate protocol
@interface MyClass : NSObject <AVAudioSessionDelegate> { [...] }
// implement 2 methods : here's an example implementation
-(void) beginInterruption {
LinphoneCall* c = linphone_core_get_current_call(theLinphoneCore);
ms_message("Sound interruption detected!");
if (c) {
linphone_core_pause_call(theLinphoneCore, c);
}
}
-(void) endInterruption {
ms_message("Sound interruption ended!");
const MSList* c = linphone_core_get_calls(theLinphoneCore);
if (c) {
ms_message("Auto resuming call");
linphone_core_resume_call(theLinphoneCore, (LinphoneCall*) c->data);
}
}
.. seealso:: http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAudioSessionDelegate_ProtocolReference/Reference/Reference.html
Declare an instance of your class as AudioSession's delegate :
.. code-block:: objective-c
[audioSession setDelegate:myClassInstance];
.. seealso:: http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAudioSession_ClassReference/Reference/Reference.html
Video
-----
Since 3.5 video support has been added to liblinphone for IOS. It requires the application to provide liblinphone with pointers to IOS's views hosting video
display and video previous. These two UIView objects must be passed to the core using functions :cpp:func:`linphone_core_set_native_video_window_id` and
:cpp:func:`linphone_core_set_native_preview_window_id`. Here under pseudo code:
.. code-block:: objective-c
UIView* display = [[UIView alloc] init];
UIView* preview = [[UIView alloc] init];
linphone_core_set_native_video_window_id(lc,(unsigned long)display);
linphone_core_set_native_preview_window_id(lc,(unsigned long)preview);
Screen rotations are also handled by liblinphone. Two positions are currently supported, namely *UIInterfaceOrientationPortrait* and *UIInterfaceOrientationLandscapeRight*.
Applications may invoke :cpp:func:`linphone_core_set_device_rotation` followed by :cpp:func:`linphone_core_update_call` to notify liblinphone of an orientation
change. Here under a speudo code to handle orientation changes
.. code-block:: c
-(void) configureOrientation:(UIInterfaceOrientation) oritentation {
int oldLinphoneOrientation = linphone_core_get_device_rotation(lc);
if (oritentation == UIInterfaceOrientationPortrait ) {
linphone_core_set_native_video_window_id(lc,(unsigned long)display-portrait);
linphone_core_set_native_preview_window_id(lc,(unsigned long)preview-portrait);
linphone_core_set_device_rotation(lc, 0);
} else if (oritentation == UIInterfaceOrientationLandscapeRight ) {
linphone_core_set_native_video_window_id(lc,(unsigned long)display-landscape);
linphone_core_set_native_preview_window_id(lc,(unsigned long)preview-landscape);
linphone_core_set_device_rotation(lc, 270);
}
if ((oldLinphoneOrientation != linphone_core_get_device_rotation(lc))
&& linphone_core_get_current_call(lc)) {
//Orientation has changed, must call update call
linphone_core_update_call(lc, linphone_core_get_current_call(lc), NULL);
}
}
DTMF feedbacks
--------------
Liblinphone provides functions :cpp:func:`to play dtmf <linphone_core_play_dtmf()>` to the local user. Usually this is used to play a sound when the user
presses a digit, inside or outside of any call. On IOS, libLinphone relies on AudioUnits for interfacing with the audio system. Unfortunately the Audio Unit
initialization is a quite long operation that may trigger a bad user experience if performed each time a DTMF is played, the sound being delayed half a
second after the press. To solve this issue and thus insure real-time precision, liblinphone introduces two functions for :cpp:func:`preloading <linphone_core_start_dtmf_stream>`
and :cpp:func:`unloading <linphone_core_start_dtmf_stream>` the underlying audio graph responsible for playing DTMFs.
For an application using function :cpp:func:`linphone_core_play_dtmf`, it is recommanded to call :cpp:func:`linphone_core_start_dtmf_stream` when entering
in foreground and #linphone_core_stop_dtmf_stream() upon entering background mode.
Plugins
-------
On iOS, plugins are built as static libraries so Liblinphone will not be able to load them at runtime dynamically. Instead, you should declare their prototypes:
.. code-block:: c
extern void libmsamr_init(MSFactory *factory);
extern void libmsx264_init(MSFactory *factory);
extern void libmsopenh264_init(MSFactory *factory);
extern void libmssilk_init(MSFactory *factory);
extern void libmsbcg729_init(MSFactory *factory);
extern void libmswebrtc_init(MSFactory *factory);
Then you should register them after the instantiation of :cpp:type:`LinphoneCore`:
.. code-block:: c
theLinphoneCore = linphone_core_new_with_config(/* options ... */);
// Load plugins if available in the linphone SDK - otherwise these calls will do nothing
MSFactory *f = linphone_core_get_ms_factory(theLinphoneCore);
libmssilk_init(f);
libmsamr_init(f);
libmsx264_init(f);
libmsopenh264_init(f);
libmsbcg729_init(f);
libmswebrtc_init(f);
linphone_core_reload_ms_plugins(theLinphoneCore, NULL);
If the plugin has not been enabled at compilation time, a stubbed library will be generated with only libplugin_init method declared, doing nothing. You should
see these trace in logs, if plugin is stubbed:
.. code-block:: none
I/lib/Could not find encoder for SILK
I/lib/Could not find decoder for SILK

View file

@ -0,0 +1,4 @@
SIP address parser API
======================
This api is useful for manipulating SIP addresses ('from' or 'to' headers).

View file

@ -0,0 +1,11 @@
Controlling media parameters
============================
Multicast
---------
Call using rtp multicast addresses are supported for both audio and video with some limitations. Limitations are, no stun, no ice, no encryption.
* Incoming call with multicast address are automatically accepted. The called party switches in a media receive only mode.
* Outgoing call willing to send media to a multicast address can activate multicast using :cpp:func:`linphone_core_enable_video_multicast`
or :cpp:func:`linphone_core_enable_audio_multicast`. The calling party switches in a media listen send only mode.

View file

@ -0,0 +1,3 @@
Miscenalleous: logs, version strings, config storage
====================================================

View file

@ -0,0 +1,2 @@
Controlling network parameters (ports, mtu…)
============================================

View file

@ -0,0 +1,76 @@
Managing proxies
================
User registration is controled by :cpp:type:`LinphoneProxyConfig` settings.
Each :cpp:type:`LinphoneProxyConfig` object can be configured with registration informations like :cpp:func:`proxy address <linphone_proxy_config_set_server_addr>`,
:cpp:func:`user id <linphone_proxy_config_set_identity>`, :cpp:func:`refresh period <linphone_proxy_config_expires>`, and so on.
A created proxy config using :cpp:func:`linphone_proxy_config_new`, once configured, must be added to :cpp:type:`LinphoneCore` using function :cpp:func:`linphone_core_add_proxy_config`.
It is recommended to set a default :cpp:type:`proxy config <LinphoneProxyConfig>` using function :cpp:func:`linphone_core_set_default_proxy`. Once done,
if :cpp:type:`proxy config <LinphoneProxyConfig>` has been configured with attribute :cpp:func:`enable register <linphone_proxy_config_enable_register>`,
next call to :cpp:func:`linphone_core_iterate` triggers SIP register.
Registration status is reported by LinphoneCoreRegistrationStateChangedCb.
This pseudo code demonstrates basic registration operations:
.. code-block:: c
LinphoneProxyConfig* proxy_cfg;
/*create proxy config*/
proxy_cfg = linphone_proxy_config_new();
/*parse identity*/
LinphoneAddress *from = linphone_address_new("sip:toto@sip.titi.com");
LinphoneAuthInfo *info;
if (password!=NULL){
info=linphone_auth_info_new(linphone_address_get_username(from),NULL,"secret",NULL,NULL); /*create authentication structure from identity*/
linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/
}
// configure proxy entries
linphone_proxy_config_set_identity(proxy_cfg,identity); /*set identity with user name and domain*/
const char* server_addr = linphone_address_get_domain(from); /*extract domain address from identity*/
linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); /* we assume domain = proxy server address*/
linphone_proxy_config_enable_register(proxy_cfg,TRUE); /*activate registration for this proxy config*/
linphone_address_destroy(from); /*release resource*/
linphone_core_add_proxy_config(lc,proxy_cfg); /*add proxy config to linphone core*/
linphone_core_set_default_proxy(lc,proxy_cfg); /*set to default proxy*/
Registration sate call back:
.. code-block:: c
static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){
printf("New registration state %s for user id [%s] at proxy [%s]\n"
,linphone_registration_state_to_string(cstate)
,linphone_proxy_config_get_identity(cfg)
,linphone_proxy_config_get_addr(cfg));
}
Authentication
--------------
Most of the time, registration requires :doc:`authentication <authentication>` to succeed. :cpp:type:`LinphoneAuthInfo` info must be either added
to :cpp:type:`LinphoneCore` using function :cpp:func:`linphone_core_add_auth_info` before :cpp:type:`LinphoneProxyConfig` is added to Linphone core, or on demand
from call back #LinphoneCoreAuthInfoRequestedCb.
Unregistration
--------------
Unregistration or any changes to :cpp:type:`LinphoneProxyConfig` must be first started by a call to function :cpp:func:`linphone_proxy_config_edit` and validated by
function :cpp:func:`linphone_proxy_config_done`.
This pseudo code shows how to unregister a user associated to a #LinphoneProxyConfig:
.. code-block:: c
LinphoneProxyConfig* proxy_cfg;
linphone_core_get_default_proxy(lc,&proxy_cfg); /* get default proxy config*/
linphone_proxy_config_edit(proxy_cfg); /*start editing proxy configuration*/
linphone_proxy_config_enable_register(proxy_cfg,FALSE); /*de-activate registration for this proxy config*/
linphone_proxy_config_done(proxy_cfg); /*initiate REGISTER with expire = 0*/
.. seealso:: A complete tutorial can be found at: :ref:`"Basic registration" <basic_registration_code_sample>` source code.

View file

@ -0,0 +1,70 @@
.. Linphone API documentation master file, created by
sphinx-quickstart on Mon Jun 19 11:58:21 2017.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Linphone API's documentation!
========================================
What is liblinphone
-------------------
Liblinphone is a high level library for bringing SIP video call functionnality
into an application. It aims at making easy the integration of the SIP
video calls into any applications. All variants of linphone are directly based
on it:
* linphone (gtk interface)
* linphonec (console interface)
* linphone for iOS
* linphone for Android
Liblinphone is GPL (see COPYING file). Please understand the licencing details
before using it!
For any use of this library beyond the rights granted to you by the
GPL license, please contact Belledonne Communications
(contact@belledonne-communications.com).
Beginners' guides
-----------------
.. toctree::
:maxdepth: 1
guides/initializing
guides/call_control
guides/call_misc
guides/media_parameters
guides/proxies
guides/network_parameters
guides/authentication
guides/buddy_list
guides/chatroom
guides/call_logs
guides/linphone_address
guides/conferencing
guides/event_api
guides/misc
guides/ios_portability
Code samples
------------
.. toctree::
:maxdepth: 1
samples/samples
API's reference documentation
-----------------------------
.. toctree::
:maxdepth: 1
reference/c/index
reference/cpp/index
reference/java/index
reference/csharp/index

View file

@ -1,19 +1,8 @@
{{#make_section}}{{{language}}} API{{/make_section}}
Index of classes
----------------
{{{title}}}
.. toctree::
:maxdepth: 1
{{#tocEntries}}
{{{entryName}}}
{{/tocEntries}}
Index of enums
--------------
.. toctree::
:maxdepth 1
enums.rst
{{#entries}}
{{{filename}}}
{{/entries}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,106 @@
.. _basic_call_code_sample:
Basic call
==========
This program is a *very* simple usage example of liblinphone. It just takes a sip-uri as first argument and attempts to call it
.. literalinclude:: helloworld.c
:language: c
.. _basic_registration_code_sample:
Basic registration
==================
This program is a *very* simple usage example of liblinphone, desmonstrating how to initiate a SIP registration from a sip uri identity
passed from the command line. First argument must be like sip:jehan@sip.linphone.org , second must be *password* . Registration is cleared
on *SIGINT*.
Example: ``registration sip:jehan@sip.linphone.org secret``
.. literalinclude:: registration.c
:language: c
.. _subscribe_notify_code_sample:
Generic subscribe/notify example
================================
This program is a *very* simple usage example of liblinphone. It demonstrates how to listen to a SIP subscription.
It then sends notify requests back periodically. First argument must be like sip:jehan@sip.linphone.org , second must be *password*.
Registration is cleared on *SIGINT*.
Example: ``registration sip:jehan@sip.linphone.org secret``
.. literalinclude:: registration.c
:language: c
.. _buddy_status_notification_code_sample:
Basic buddy status notification
===============================
This program is a *very* simple usage example of liblinphone, demonstrating how to initiate SIP subscriptions and receive
notifications from a sip uri identity passed from the command line. Argument must be like sip:jehan@sip.linphone.org .
Subscription is cleared on *SIGINT* signal.
Example: ``budy_list sip:jehan@sip.linphone.org``
.. literalinclude:: buddy_status.c
:language: c
.. _chatroom_code_sample:
Chat room and messaging
=======================
This program is a *very* simple usage example of liblinphone, desmonstrating how to send/receive SIP MESSAGE from a sip uri
identity passed from the command line. Argument must be like sip:jehan@sip.linphone.org .
Example: ``chatroom sip:jehan@sip.linphone.org``
.. literalinclude:: chatroom.c
:language: c
.. _file_transfer_code_sample:
File transfer
=============
.. literalinclude:: filetransfer.c
:language: c
.. _RT text receiver_code_sample:
Real Time Text Receiver
=======================
This program is able to receive chat message in real time on port 5060. Use realtimetext_sender to generate chat message
Example: ``./realtimetext_receiver``
.. literalinclude:: realtimetext_sender.c
:language: c
.. _RT_text_sender_code_sample:
Real Time Text Sender
=====================
This program just send chat message in real time to dest uri. Use realtimetext_receiver to receive message.
Example: ``./realtimetext_sender sip:localhost:5060``
.. literalinclude:: realtimetext_sender.c
:language: c

View file

@ -1,24 +0,0 @@
.. Linphone API documentation master file, created by
sphinx-quickstart on Mon Jun 19 11:58:21 2017.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Linphone API's documentation!
========================================
.. toctree::
:maxdepth: 1
:caption: Contents:
c/index.rst
cpp/index.rst
csharp/index.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View file

@ -24,12 +24,22 @@ if (ENABLE_TOOLS)
if (IOS)
set(USE_BUNDLE MACOSX_BUNDLE)
endif()
file(GLOB EXECUTABLES_SOURCE RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c")
foreach(EXECUTABLE ${EXECUTABLES_SOURCE})
set(LINPHONE_C_EXAMPLES_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/buddy_status.c
${CMAKE_CURRENT_SOURCE_DIR}/chatroom.c
${CMAKE_CURRENT_SOURCE_DIR}/filetransfer.c
${CMAKE_CURRENT_SOURCE_DIR}/helloworld.c
${CMAKE_CURRENT_SOURCE_DIR}/notify.c
${CMAKE_CURRENT_SOURCE_DIR}/realtimetext_receiver.c
${CMAKE_CURRENT_SOURCE_DIR}/realtimetext_sender.c
${CMAKE_CURRENT_SOURCE_DIR}/registration.c
PARENT_SCOPE
)
foreach(EXECUTABLE ${LINPHONE_C_EXAMPLES_SOURCE})
string(REPLACE ".c" "" EXECUTABLE_NAME ${EXECUTABLE})
bc_apply_compile_flags(${EXECUTABLE} STRICT_OPTIONS_CPP STRICT_OPTIONS_C)
add_executable(${EXECUTABLE_NAME} ${USE_BUNDLE} ${EXECUTABLE})
target_link_libraries(${EXECUTABLE_NAME} ${LINPHONE_LIBS_FOR_TOOLS} ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES})
target_link_libraries(${EXECUTABLE_NAME} ${LINPHONE_LIBS_FOR_TOOLS} ${MEDIASTREAMER2_LIBRARIES} ${ORTP_LIBRARIES} ${BCTOOLBOX_CORE_LIBRARIES} ${XSD_LIBRARIES})
set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}")
if (NOT IOS)
install(TARGETS ${EXECUTABLE_NAME}

View file

@ -45,8 +45,8 @@ static void stop(int signum){
* function invoked to report file transfer progress.
* */
static void file_transfer_progress_indication(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total) {
const LinphoneAddress* from_address = linphone_chat_message_get_from(message);
const LinphoneAddress* to_address = linphone_chat_message_get_to(message);
const LinphoneAddress* from_address = linphone_chat_message_get_from_address(message);
const LinphoneAddress* to_address = linphone_chat_message_get_to_address(message);
char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address);
printf(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", (int)((offset *100)/total)
,(linphone_chat_message_is_outgoing(message)?"sent":"received")
@ -70,7 +70,7 @@ static void file_transfer_received(LinphoneChatMessage *message, const LinphoneC
file = (FILE*)linphone_chat_message_get_user_data(message);
if (linphone_buffer_is_empty(buffer)) {
printf("File transfert completed\n");
linphone_chat_message_destroy(message);
linphone_chat_message_unref(message);
fclose(file);
running=FALSE;
} else { /* store content on a file*/
@ -95,7 +95,7 @@ static LinphoneBuffer * file_transfer_send(LinphoneChatMessage *message, const L
* Call back to get delivery status of a message
* */
static void linphone_file_transfer_state_changed(LinphoneChatMessage* msg,LinphoneChatMessageState state) {
const LinphoneAddress* to_address = linphone_chat_message_get_to(msg);
const LinphoneAddress* to_address = linphone_chat_message_get_to_address(msg);
char *to = linphone_address_as_string(to_address);
printf("File transfer sent to [%s] delivery status is [%s] \n" , to
, linphone_chat_message_state_to_string(state));

View file

@ -18,9 +18,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/core.h"
#include "linphone/im_encryption_engine.h"
#include "private.h"
#include "c-wrapper/c-wrapper.h"
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneImEncryptionEngineCbs);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneImEncryptionEngineCbs, belle_sip_object_t,

View file

@ -18,8 +18,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/core.h"
#include "private.h"
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneImNotifPolicy);
@ -30,7 +33,6 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneImNotifPolicy, belle_sip_object_t,
FALSE
);
static void load_im_notif_policy_from_config(LinphoneImNotifPolicy *policy) {
bctbx_list_t *default_list = bctbx_list_append(NULL, (void *)"all");
bctbx_list_t *values = lp_config_get_string_list(policy->lc->config, "sip", "im_notif_policy", default_list);
@ -203,6 +205,8 @@ LinphoneImNotifPolicy * linphone_core_get_im_notif_policy(const LinphoneCore *lc
}
void linphone_core_create_im_notif_policy(LinphoneCore *lc) {
if (lc->im_notif_policy)
linphone_im_notif_policy_unref(lc->im_notif_policy);
lc->im_notif_policy = belle_sip_object_new(LinphoneImNotifPolicy);
lc->im_notif_policy->lc = lc;
load_im_notif_policy_from_config(lc->im_notif_policy);

View file

@ -22,11 +22,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "linphone/api/c-content.h"
#include "linphone/core.h"
#include "private.h"
#include "linphone/lpconfig.h"
#include "c-wrapper/c-wrapper.h"
struct _LinphoneInfoMessage{
belle_sip_object_t base;
@ -76,12 +77,6 @@ LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore *lc){
return belle_sip_object_new(LinphoneInfoMessage);
}
LinphoneStatus linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info) {
SalBodyHandler *body_handler = sal_body_handler_from_content(info->content);
sal_op_set_sent_custom_header(call->op, info->headers);
return sal_send_info(call->op,NULL, NULL, body_handler);
}
void linphone_info_message_add_header(LinphoneInfoMessage *im, const char *name, const char *value){
im->headers=sal_custom_header_append(im->headers, name, value);
}
@ -90,21 +85,25 @@ const char *linphone_info_message_get_header(const LinphoneInfoMessage *im, cons
return sal_custom_header_find(im->headers,name);
}
void linphone_info_message_set_content(LinphoneInfoMessage *im, const LinphoneContent *content){
im->content=linphone_content_copy(content);
void linphone_info_message_set_content (LinphoneInfoMessage *im, const LinphoneContent *content) {
if (im->content)
linphone_content_unref(im->content);
im->content = linphone_content_copy(content);
}
const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMessage *im){
return (im->content && linphone_content_get_type(im->content)) ? im->content : NULL;
}
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, SalBodyHandler *body_handler){
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call){
LinphoneInfoMessage *info=linphone_core_create_info_message(lc);
info->headers=sal_custom_header_clone(sal_op_get_recv_custom_header(op));
if (body_handler) info->content=linphone_content_from_sal_body_handler(body_handler);
linphone_call_notify_info_message_received(call, info);
linphone_info_message_unref(info);
}
SalCustomHeader *linphone_info_message_get_headers (const LinphoneInfoMessage *im) {
return im->headers;
}
void linphone_info_message_set_headers (LinphoneInfoMessage *im, const SalCustomHeader *headers) {
if (im->headers) {
sal_custom_header_free(im->headers);
im->headers = nullptr;
}
if (headers)
im->headers = sal_custom_header_clone(headers);
}

View file

@ -1,119 +0,0 @@
/*
linphone
Copyright (C) 2017 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.
*/
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
#if TARGET_OS_IPHONE
#include "private.h"
#include "platform-helpers.h"
namespace LinphonePrivate{
class IosPlatformHelpers : public PlatformHelpers{
public:
IosPlatformHelpers(LinphoneCore *lc, void *system_context);
virtual void setDnsServers();
virtual void acquireWifiLock();
virtual void releaseWifiLock();
virtual void acquireMcastLock();
virtual void releaseMcastLock();
virtual void acquireCpuLock();
virtual void releaseCpuLock();
~IosPlatformHelpers();
private:
void bgTaskTimeout();
static void sBgTaskTimeout(void *data);
long int mCpuLockTaskId;
int mCpuLockCount;
};
IosPlatformHelpers::IosPlatformHelpers(LinphoneCore *lc, void *system_context) : PlatformHelpers(lc) {
mCpuLockCount = 0;
mCpuLockTaskId = 0;
ms_message("IosPlatformHelpers is fully initialised");
}
IosPlatformHelpers::~IosPlatformHelpers(){
}
void IosPlatformHelpers::setDnsServers(){
}
void IosPlatformHelpers::acquireWifiLock(){
}
void IosPlatformHelpers::releaseWifiLock(){
}
void IosPlatformHelpers::acquireMcastLock(){
}
void IosPlatformHelpers::releaseMcastLock(){
}
void IosPlatformHelpers::bgTaskTimeout(){
ms_error("IosPlatformHelpers: the system requests that the cpu lock is released now.");
if (mCpuLockTaskId != 0){
belle_sip_end_background_task(mCpuLockTaskId);
mCpuLockTaskId = 0;
}
}
void IosPlatformHelpers::sBgTaskTimeout(void *data){
IosPlatformHelpers *zis = (IosPlatformHelpers*)data;
zis->bgTaskTimeout();
}
void IosPlatformHelpers::acquireCpuLock(){
if (mCpuLockCount == 0){
/* on iOS, cpu lock is implemented by a long running task (obcj-C) and it is abstracted by belle-sip,
so let's use belle-sip directly.*/
mCpuLockTaskId = belle_sip_begin_background_task("Liblinphone cpu lock", sBgTaskTimeout, this);
}
mCpuLockCount++;
}
void IosPlatformHelpers::releaseCpuLock(){
mCpuLockCount--;
if (mCpuLockCount == 0){
if (mCpuLockTaskId != 0){
belle_sip_end_background_task(mCpuLockTaskId);
mCpuLockTaskId = 0;
}else{
ms_error("IosPlatformHelpers::releaseCpuLock(): too late, the lock has been released already by the system.");
}
}
}
PlatformHelpers *createIosPlatformHelpers(LinphoneCore *lc, void *system_context){
return new IosPlatformHelpers(lc, system_context);
}
}//end of namespace
#endif

View file

@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/api/c-content.h"
#include "lime.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -93,21 +95,21 @@ int lime_getCachedSndKeysByURI(void *cachedb, limeURIKeys_t *associatedKeys) {
/* retrieve values : peerZid, sndKey, sndSId, sndIndex, valid from columns 1,2,3,4,5 */
length = sqlite3_column_bytes(sqlStmt, 1);
if (length==12) { /* peerZID */
memcpy(currentPeerKey->peerZID, sqlite3_column_blob(sqlStmt, 1), length);
memcpy(currentPeerKey->peerZID, sqlite3_column_blob(sqlStmt, 1), (size_t)length);
} else { /* something wrong with that one, skip it */
continue;
}
length = sqlite3_column_bytes(sqlStmt, 2);
if (length==32) { /* sndKey */
memcpy(currentPeerKey->key, sqlite3_column_blob(sqlStmt, 2), length);
memcpy(currentPeerKey->key, sqlite3_column_blob(sqlStmt, 2), (size_t)length);
} else { /* something wrong with that one, skip it */
continue;
}
length = sqlite3_column_bytes(sqlStmt, 3);
if (length==32) { /* sndSId */
memcpy(currentPeerKey->sessionId, sqlite3_column_blob(sqlStmt, 3), length);
memcpy(currentPeerKey->sessionId, sqlite3_column_blob(sqlStmt, 3), (size_t)length);
} else { /* something wrong with that one, skip it */
continue;
}
@ -126,14 +128,14 @@ int lime_getCachedSndKeysByURI(void *cachedb, limeURIKeys_t *associatedKeys) {
length = sqlite3_column_bytes(sqlStmt, 5);
if (length==8) { /* sndIndex : 8 bytes of a int64_t, stored as a blob in big endian */
uint8_t *validity = (uint8_t *)sqlite3_column_blob(sqlStmt, 5);
validityTimeSpec.tv_sec = ((uint64_t)(validity[0]))<<56 |
validityTimeSpec.tv_sec = (int64_t)(((uint64_t)(validity[0]))<<56 |
((uint64_t)(validity[1]))<<48 |
((uint64_t)(validity[2]))<<40 |
((uint64_t)(validity[3]))<<32 |
((uint64_t)(validity[4]))<<24 |
((uint64_t)(validity[5]))<<16 |
((uint64_t)(validity[6]))<<8 |
((uint64_t)(validity[7]));
((uint64_t)(validity[7])));
} else { /* something wrong with that one, skip it */
continue;
}
@ -144,7 +146,7 @@ int lime_getCachedSndKeysByURI(void *cachedb, limeURIKeys_t *associatedKeys) {
/* check validity */
bctbx_get_utc_cur_time(&currentTimeSpec);
if (validityTimeSpec.tv_sec == 0 || bctbx_timespec_compare(&currentTimeSpec, &validityTimeSpec)<0) {
associatedKeys->associatedZIDNumber +=1;
associatedKeys->associatedZIDNumber++;
/* extend array of pointer to limeKey_t structures to add the one we found */
associatedKeys->peerKeys = (limeKey_t **)bctbx_realloc(associatedKeys->peerKeys, (associatedKeys->associatedZIDNumber)*sizeof(limeKey_t *));
@ -210,7 +212,7 @@ int lime_getCachedRcvKeyByZid(void *cachedb, limeKey_t *associatedKey, const cha
/* retrieve values : rcvKey, rcvSId, rcvIndex from columns 1,2,3 */
length = sqlite3_column_bytes(sqlStmt, 1);
if (length==32) { /* rcvKey */
memcpy(associatedKey->key, sqlite3_column_blob(sqlStmt, 1), length);
memcpy(associatedKey->key, sqlite3_column_blob(sqlStmt, 1), (size_t)length);
} else { /* something wrong */
ms_error("[LIME] Get Cached Rcv Key by Zid fetched a rcvKey with wrong length");
sqlite3_finalize(sqlStmt);
@ -219,7 +221,7 @@ int lime_getCachedRcvKeyByZid(void *cachedb, limeKey_t *associatedKey, const cha
length = sqlite3_column_bytes(sqlStmt, 2);
if (length==32) { /* rcvSId */
memcpy(associatedKey->sessionId, sqlite3_column_blob(sqlStmt, 2), length);
memcpy(associatedKey->sessionId, sqlite3_column_blob(sqlStmt, 2), (size_t)length);
} else { /* something wrong */
ms_error("[LIME] Get Cached Rcv Key by Zid fetched a rcvSid with wrong length");
sqlite3_finalize(sqlStmt);
@ -261,14 +263,14 @@ int lime_setCachedKey(void *cachedb, limeKey_t *associatedKey, uint8_t role, uin
uint8_t *colValues[4];
uint8_t sessionIndex[4]; /* buffer to hold the uint32_t buffer index in big endian */
size_t colLength[] = {32, 32, 4, 8}; /* data length: keys and session ID : 32 bytes, Index: 4 bytes(uint32_t), validity : 8 bytes(UTC time as int64_t) */
int colNums;
uint8_t colNums;
if (cachedb == NULL || associatedKey == NULL) { /* there is no cache return error */
return LIME_INVALID_CACHE;
}
/* wrap values to be written */
sessionIndex[0] = (associatedKey->sessionIndex>>24)&0xFF;
sessionIndex[0] = (uint8_t)((associatedKey->sessionIndex>>24)&0xFF);
sessionIndex[1] = (associatedKey->sessionIndex>>16)&0xFF;
sessionIndex[2] = (associatedKey->sessionIndex>>8)&0xFF;
sessionIndex[3] = (associatedKey->sessionIndex)&0xFF;
@ -279,16 +281,16 @@ int lime_setCachedKey(void *cachedb, limeKey_t *associatedKey, uint8_t role, uin
/* shall we update valid column? Enforce only when receiver, if timeSpan is 0, just ignore */
if (validityTimeSpan > 0 && role == LIME_RECEIVER) {
bctbx_get_utc_cur_time(&currentTime);
bctbx_timespec_add(&currentTime, validityTimeSpan);
bctbx_timespec_add(&currentTime, (int64_t)validityTimeSpan);
/* store the int64_t in big endian in the cache(cache is not typed, all data seen as blob) */
colValues[3][0] = (currentTime.tv_sec>>56)&0xFF;
colValues[3][1] = (currentTime.tv_sec>>48)&0xFF;
colValues[3][2] = (currentTime.tv_sec>>40)&0xFF;
colValues[3][3] = (currentTime.tv_sec>>32)&0xFF;
colValues[3][4] = (currentTime.tv_sec>>24)&0xFF;
colValues[3][5] = (currentTime.tv_sec>>16)&0xFF;
colValues[3][6] = (currentTime.tv_sec>>8)&0xFF;
colValues[3][7] = (currentTime.tv_sec)&0xFF;
colValues[3][0] = (uint8_t)((currentTime.tv_sec>>56)&0xFF);
colValues[3][1] = (uint8_t)((currentTime.tv_sec>>48)&0xFF);
colValues[3][2] = (uint8_t)((currentTime.tv_sec>>40)&0xFF);
colValues[3][3] = (uint8_t)((currentTime.tv_sec>>32)&0xFF);
colValues[3][4] = (uint8_t)((currentTime.tv_sec>>24)&0xFF);
colValues[3][5] = (uint8_t)((currentTime.tv_sec>>16)&0xFF);
colValues[3][6] = (uint8_t)((currentTime.tv_sec>>8)&0xFF);
colValues[3][7] = (uint8_t)((currentTime.tv_sec)&0xFF);
colNums = 4;
} else {
@ -296,7 +298,11 @@ int lime_setCachedKey(void *cachedb, limeKey_t *associatedKey, uint8_t role, uin
}
/* update cache */
return bzrtp_cache_write(cachedb, associatedKey->zuid, "lime", role==LIME_SENDER?colNamesSender:colNamesReceiver, colValues, colLength, colNums);
return bzrtp_cache_write(
cachedb, associatedKey->zuid, "lime",
role == LIME_SENDER ? colNamesSender : colNamesReceiver,
colValues, colLength, colNums
);
}
/**
@ -315,7 +321,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;
@ -396,6 +402,8 @@ int lime_encryptMessage(limeKey_t *key, const uint8_t *plainMessage, uint32_t me
int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {
bctbx_aes_gcm_context_t *gcmContext;
if (key == NULL) return -1;
if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */
/* key contains 192bits of key || 64 bits of Initialisation Vector, no additional data */
gcmContext = bctbx_aes_gcm_context_new(key, 24, NULL, 0, key+24, 8, BCTBX_GCM_ENCRYPT);
@ -417,6 +425,8 @@ int lime_encryptFile(void **cryptoContext, unsigned char *key, size_t length, ch
int lime_decryptFile(void **cryptoContext, unsigned char *key, size_t length, char *plain, char *cipher) {
bctbx_aes_gcm_context_t *gcmContext;
if (key == NULL) return -1;
if (*cryptoContext == NULL) { /* first call to the function, allocate a crypto context and initialise it */
/* key contains 192bits of key || 64 bits of Initialisation Vector, no additional data */
gcmContext = bctbx_aes_gcm_context_new(key, 24, NULL, 0, key+24, 8, BCTBX_GCM_DECRYPT);
@ -569,8 +579,8 @@ int lime_createMultipartMessage(void *cachedb, const char *contentType, uint8_t
/* dump the whole message doc into the output */
xmlDocDumpFormatMemoryEnc(xmlOutputMessage, &local_output, &xmlStringLength, "UTF-8", 0);
*output = (uint8_t *)ms_malloc(xmlStringLength + 1);
memcpy(*output, local_output, xmlStringLength);
*output = (uint8_t *)ms_malloc((size_t)xmlStringLength + 1);
memcpy(*output, local_output, (size_t)xmlStringLength);
(*output)[xmlStringLength] = '\0';
xmlFree(local_output);
@ -603,7 +613,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
/* retrieve selfZID from cache, and convert it to an Hexa buffer to easily match it against hex string containg in xml message as pzid */
if (bzrtp_getSelfZID(cachedb, selfURI, selfZid, NULL) != 0) {
ms_error("[LIME] Couldn't get self ZID");
ms_error("[LIME] Couldn't get self ZID");
return LIME_UNABLE_TO_DECRYPT_MESSAGE;
}
bctbx_int8_to_str(selfZidHex, selfZid, 12);
@ -613,13 +623,13 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
xml_ctx->doc = xmlReadDoc((const unsigned char*)message, 0, NULL, 0);
if (xml_ctx->doc == NULL) {
ms_error("[LIME] XML doc is null");
ms_error("[LIME] XML doc is null");
retval = LIME_INVALID_ENCRYPTED_MESSAGE;
goto error;
}
if (linphone_create_xml_xpath_context(xml_ctx) < 0) {
ms_error("[LIME] Couldn't create xml xpath context");
ms_error("[LIME] Couldn't create xml xpath context");
retval = LIME_INVALID_ENCRYPTED_MESSAGE;
goto error;
}
@ -644,7 +654,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
if ((msg_object != NULL) && (msg_object->nodesetval != NULL)) {
for (i = 1; i <= msg_object->nodesetval->nodeNr; i++) {
char *currentZidHex;
char *encryptedMessageb64;
char *encryptedContentTypeb64;
snprintf(xpath_str, sizeof(xpath_str), "/doc/msg[%i]/pzid", i);
@ -682,7 +692,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
/* do we have retrieved correctly all the needed data */
if (encryptedMessage == NULL) {
ms_error("[LIME] Encrypted message is null, something went wrong...");
ms_error("[LIME] Encrypted message is null, something went wrong...");
retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
goto error;
}
@ -692,7 +702,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
/* something wen't wrong with the cache, this shall never happen */
uint8_t associatedKeyIndexHex[9];
bctbx_uint32_to_str(associatedKeyIndexHex, associatedKey.sessionIndex);
ms_error("[LIME] Session index [%s] < associated key's session index [%s], should not happen !", sessionIndexHex, associatedKeyIndexHex);
ms_error("[LIME] Session index [%s] < associated key's session index [%s], should not happen !", sessionIndexHex, associatedKeyIndexHex);
ms_free(encryptedMessage);
retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
goto error;
@ -700,7 +710,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
if ((usedSessionIndex - associatedKey.sessionIndex > MAX_DERIVATION_NUMBER) ) {
/* we missed to many messages, ask for a cache reset via a ZRTP call */
ms_error("[LIME] Too many messages missed (%i), cache should be reset by ZRTP call", usedSessionIndex - associatedKey.sessionIndex);
ms_error("[LIME] Too many messages missed (%i), cache should be reset by ZRTP call", usedSessionIndex - associatedKey.sessionIndex);
ms_free(encryptedMessage);
retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
goto error;
@ -709,7 +719,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
if (associatedKey.sessionIndex != usedSessionIndex) {
uint8_t associatedKeyIndexHex[9];
bctbx_uint32_to_str(associatedKeyIndexHex, associatedKey.sessionIndex);
ms_warning("LIME] unexpected session index [%s] received from [%s] (expected [%s]), [%i] messages will be discarded",
ms_warning("LIME] unexpected session index [%s] received from [%s] (expected [%s]), [%i] messages will be discarded",
sessionIndexHex, peerURI, associatedKeyIndexHex, usedSessionIndex-associatedKey.sessionIndex);
}
@ -724,7 +734,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
if (retval != 0) {
ms_free(*output);
*output = NULL;
ms_error("[LIME] Couldn't decrypt message");
ms_error("[LIME] Couldn't decrypt message");
retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
goto error;
}
@ -737,7 +747,7 @@ int lime_decryptMultipartMessage(void *cachedb, uint8_t *message, const char *se
if (retval != 0) {
ms_free(*content_type);
*content_type = NULL;
ms_error("[LIME] Couldn't decrypt content type");
ms_error("[LIME] Couldn't decrypt content type");
retval = LIME_UNABLE_TO_DECRYPT_MESSAGE;
goto error;
}
@ -757,17 +767,21 @@ error:
bool_t linphone_chat_room_lime_available(LinphoneChatRoom *cr) {
if (cr) {
switch (linphone_core_lime_enabled(cr->lc)) {
switch (linphone_core_lime_enabled(linphone_chat_room_get_core(cr))) {
case LinphoneLimeDisabled: return FALSE;
case LinphoneLimeMandatory:
case LinphoneLimePreferred: {
void *zrtp_cache_db = linphone_core_get_zrtp_cache_db(cr->lc);
void *zrtp_cache_db = linphone_core_get_zrtp_cache_db(linphone_chat_room_get_core(cr));
if (zrtp_cache_db != NULL) {
bool_t res;
limeURIKeys_t associatedKeys;
char *peer = ms_strdup_printf("%s:%s@%s" , linphone_address_get_scheme(linphone_chat_room_get_peer_address(cr))
, linphone_address_get_username(linphone_chat_room_get_peer_address(cr))
, linphone_address_get_domain(linphone_chat_room_get_peer_address(cr)));
const LinphoneAddress *peerAddr = linphone_chat_room_get_peer_address(cr);
char *peer = ms_strdup_printf(
"%s:%s@%s",
linphone_address_get_scheme(peerAddr),
linphone_address_get_username(peerAddr),
linphone_address_get_domain(peerAddr)
);
/* retrieve keys associated to the peer URI */
associatedKeys.peerURI = bctbx_strdup(peer);
associatedKeys.selfURI = NULL; /* TODO : there is no sender associated to chatroom so check for any local URI available, shall we add sender to chatroom? */
@ -790,7 +804,9 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
LinphoneCore *lc = linphone_im_encryption_engine_get_core(engine);
int errcode = -1;
/* check if we have a xml/cipher message to be decrypted */
if (msg->content_type && (strcmp("xml/cipher", msg->content_type) == 0 || strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", msg->content_type) == 0)) {
if (linphone_chat_message_get_content_type(msg) &&
(strcmp("xml/cipher", linphone_chat_message_get_content_type(msg)) == 0 ||
strcmp("application/cipher.vnd.gsma.rcs-ft-http+xml", linphone_chat_message_get_content_type(msg)) == 0)) {
errcode = 0;
int retval;
void *zrtp_cache_db = NULL; /* use a void * instead of sqlite3 * to avoid problems and ifdef when SQLITE is not available(the get function shall return NULL in that case) */
@ -799,7 +815,7 @@ 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", msg->content_type);
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) {
@ -807,14 +823,23 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
errcode = 500;
return errcode;
}
peerUri = ms_strdup_printf("%s:%s@%s" , linphone_address_get_scheme(msg->from)
, linphone_address_get_username(msg->from)
, linphone_address_get_domain(msg->from));
selfUri = ms_strdup_printf("%s:%s@%s" , linphone_address_get_scheme(msg->to)
, linphone_address_get_username(msg->to)
, linphone_address_get_domain(msg->to));
const LinphoneAddress *fromAddr = linphone_chat_message_get_from_address(msg);
peerUri = ms_strdup_printf(
"%s:%s@%s",
linphone_address_get_scheme(fromAddr),
linphone_address_get_username(fromAddr),
linphone_address_get_domain(fromAddr)
);
retval = lime_decryptMultipartMessage(zrtp_cache_db, (uint8_t *)msg->message, selfUri, peerUri, &decrypted_body, &decrypted_content_type,
const LinphoneAddress *toAddr = linphone_chat_message_get_to_address(msg);
selfUri = ms_strdup_printf(
"%s:%s@%s",
linphone_address_get_scheme(toAddr),
linphone_address_get_username(toAddr),
linphone_address_get_domain(toAddr)
);
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")));
ms_free(peerUri);
ms_free(selfUri);
@ -825,17 +850,15 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
return errcode;
} else {
/* swap encrypted message with plain text message */
if (msg->message) {
ms_free(msg->message);
}
msg->message = (char *)decrypted_body;
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", msg->content_type) == 0) {
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 {
linphone_chat_message_set_content_type(msg, "text/plain");
@ -843,7 +866,7 @@ int lime_im_encryption_engine_process_incoming_message_cb(LinphoneImEncryptionEn
}
}
} else {
ms_message("Content type is unknown (%s), don't try to decrypt it", msg->content_type);
ms_message("Content type is unknown (%s), don't try to decrypt it", linphone_chat_message_get_content_type(msg));
}
return errcode;
}
@ -852,17 +875,17 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEn
LinphoneCore *lc = linphone_im_encryption_engine_get_core(engine);
int errcode = -1;
const char *new_content_type = "xml/cipher";
if(linphone_core_lime_enabled(room->lc)) {
if(linphone_core_lime_enabled(linphone_chat_room_get_core(room))) {
if (linphone_chat_room_lime_available(room)) {
void *zrtp_cache_db = NULL; /* use a void * instead of sqlite3 * to avoid problems and ifdef when SQLITE is not available(the get function shall return NULL in that case) */
if (msg->content_type) {
if (strcmp(msg->content_type, "application/vnd.gsma.rcs-ft-http+xml") == 0) {
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(msg->content_type, "application/im-iscomposing+xml") == 0) {
} else if (strcmp(linphone_chat_message_get_content_type(msg), "application/im-iscomposing+xml") == 0) {
/* We don't encrypt composing messages */
return errcode;
}
@ -877,23 +900,29 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEn
} else {
int retval;
uint8_t *crypted_body = NULL;
char *peerUri = ms_strdup_printf("%s:%s@%s" , linphone_address_get_scheme(linphone_chat_room_get_peer_address(room))
, linphone_address_get_username(linphone_chat_room_get_peer_address(room))
, linphone_address_get_domain(linphone_chat_room_get_peer_address(room)));
char *selfUri = ms_strdup_printf("%s:%s@%s" , linphone_address_get_scheme(msg->from)
, linphone_address_get_username(msg->from)
, linphone_address_get_domain(msg->from));
const LinphoneAddress *peerAddr = linphone_chat_room_get_peer_address(room);
char *peerUri = ms_strdup_printf(
"%s:%s@%s",
linphone_address_get_scheme(peerAddr),
linphone_address_get_username(peerAddr),
linphone_address_get_domain(peerAddr)
);
const LinphoneAddress *fromAddr = linphone_chat_message_get_from_address(msg);
char *selfUri = ms_strdup_printf(
"%s:%s@%s",
linphone_address_get_scheme(fromAddr),
linphone_address_get_username(fromAddr),
linphone_address_get_domain(fromAddr)
);
retval = lime_createMultipartMessage(zrtp_cache_db, msg->content_type, (uint8_t *)msg->message, selfUri, peerUri, &crypted_body);
retval = lime_createMultipartMessage(zrtp_cache_db, linphone_chat_message_get_content_type(msg), (uint8_t *)linphone_chat_message_get_text(msg), selfUri, peerUri, &crypted_body);
if (retval != 0) { /* fail to encrypt */
ms_warning("Unable to encrypt message for %s : %s", room->peer, lime_error_code_to_string(retval));
ms_warning("Unable to encrypt message for %s : %s", peerUri, lime_error_code_to_string(retval));
if (crypted_body) ms_free(crypted_body);
errcode = 488;
} else { /* encryption ok, swap plain text message body by encrypted one */
if (msg->message) {
ms_free(msg->message);
}
msg->message = (char *)crypted_body;
linphone_chat_message_set_text(msg, (char *)crypted_body);
ms_free(crypted_body);
linphone_chat_message_set_content_type(msg, new_content_type);
}
ms_free(peerUri);
@ -910,34 +939,51 @@ int lime_im_encryption_engine_process_outgoing_message_cb(LinphoneImEncryptionEn
}
int lime_im_encryption_engine_process_downloading_file_cb(LinphoneImEncryptionEngine *engine, LinphoneChatMessage *msg, size_t offset, const uint8_t *buffer, size_t size, uint8_t *decrypted_buffer) {
if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1;
if (buffer == NULL || size == 0) {
return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL);
}
return lime_decryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information),
(unsigned char *)linphone_content_get_key(msg->file_transfer_information), size, (char *)decrypted_buffer,
(char *)buffer);
LinphoneContent *content = linphone_chat_message_get_file_transfer_information(msg);
if (!content)
return -1;
if (!linphone_content_get_key(content))
return -1;
if (!buffer || size == 0)
return lime_decryptFile(linphone_content_get_cryptoContext_address(content), NULL, 0, NULL, NULL);
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) {
size_t file_size = linphone_content_get_size(msg->file_transfer_information);
if (linphone_content_get_key(msg->file_transfer_information) == NULL) return -1;
if (buffer == NULL || *size == 0) {
return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information), NULL, 0, NULL, NULL);
}
LinphoneContent *content = linphone_chat_message_get_file_transfer_information(msg);
if (!content)
return -1;
if (!linphone_content_get_key(content))
return -1;
if (!buffer || *size == 0)
return lime_encryptFile(linphone_content_get_cryptoContext_address(content), NULL, 0, NULL, NULL);
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);
}
return lime_encryptFile(linphone_content_get_cryptoContext_address(msg->file_transfer_information),
(unsigned char *)linphone_content_get_key(msg->file_transfer_information), *size,
(char *)buffer, (char *)encrypted_buffer);
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) {
@ -950,7 +996,9 @@ void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneImEncryptio
/* generate a random 192 bits key + 64 bits of initial vector and store it into the
* file_transfer_information->key field of the msg */
sal_get_random_bytes((unsigned char *)keyBuffer, FILE_TRANSFER_KEY_SIZE);
linphone_content_set_key(msg->file_transfer_information, keyBuffer, FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */
LinphoneContent *content = linphone_chat_message_get_file_transfer_information(msg);
if (content)
linphone_content_set_key(content, keyBuffer, FILE_TRANSFER_KEY_SIZE); /* key is duplicated in the content private structure */
}
#else /* HAVE_LIME */
@ -996,7 +1044,7 @@ bool_t lime_im_encryption_engine_is_file_encryption_enabled_cb(LinphoneImEncrypt
return FALSE;
}
void lime_im_encryption_engine_generate_file_transfer_key_cb(LinphoneImEncryptionEngine *engine, LinphoneChatRoom *room, LinphoneChatMessage *msg) {
}
#endif /* 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

@ -21,8 +21,11 @@
*/
#include "linphone/tunnel.h"
#include "private.h"
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
struct _LinphoneTunnelConfig {
belle_sip_object_t base;
@ -139,6 +142,3 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneTunnelConfig, belle_sip_object_t,
NULL, // marshal
FALSE
);

View file

@ -38,6 +38,14 @@ LinphoneTunnel* linphone_core_get_tunnel(const LinphoneCore *lc){
void linphone_tunnel_destroy(LinphoneTunnel *tunnel){
}
LinphoneTunnel *linphone_tunnel_ref(LinphoneTunnel *tunnel) {
ms_warning("linphone_tunnel_ref() - stubbed, no implementation");
return tunnel;
}
void linphone_tunnel_unref(LinphoneTunnel *tunnel) {
ms_warning("linphone_tunnel_unref() - stubbed, no implementation");
}
void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config){
ms_warning("linphone_tunnel_add_server() - stubbed, no implementation");

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

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

@ -17,13 +17,16 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <map>
#include <algorithm>
#include <mediastreamer2/mscommon.h>
#include <belle-sip/object.h>
#include <map>
#include <bctoolbox/logging.h>
#include <belle-sip/object.h>
#include <mediastreamer2/mscommon.h>
#include "linphone/logging.h"
#include "private.h"
#include "c-wrapper/c-wrapper.h"
#include "logging-private.h"
@ -69,7 +72,7 @@ LinphoneLogLevel _bctbx_log_level_to_linphone_log_level(BctbxLogLevel level) {
if (response != tmap.cend()) {
return response->first;
} else {
ms_fatal("%s(): invalid argument [%d]", __FUNCTION__, level);
ms_warning("%s(): invalid argurement [%d]", __FUNCTION__, level);
return LinphoneLogLevelDebug;
}
}
@ -84,7 +87,7 @@ unsigned int _bctbx_log_mask_to_linphone_log_mask(unsigned int mask) {
}
}
if (mask != 0) {
ms_warning("%s(): invalid flag set in mask [%x]", __FUNCTION__, mask);
ms_fatal("%s(): invalid flag set in mask [%x]", __FUNCTION__, mask);
}
return res;
}
@ -124,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;
}
@ -132,7 +136,6 @@ static LinphoneLoggingService *_linphone_logging_service_new(void) {
service->log_handler = bctbx_create_log_handler(_log_handler_on_message_written_cb, _log_handler_destroy_cb, service);
service->cbs = _linphone_logging_service_cbs_new();
bctbx_add_log_handler(service->log_handler);
return service;
}
@ -156,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);
}
@ -177,11 +181,11 @@ LinphoneLoggingServiceCbs *linphone_logging_service_get_callbacks(const Linphone
static const char *_linphone_logging_service_log_domains[] = {
"bctbx",
"belle-sip",
"ortp",
"bzrtp",
"mediastreamer",
BELLE_SIP_LOG_DOMAIN,
BCTBX_LOG_DOMAIN,
"bzrtp",
BCTBX_LOG_DOMAIN, /* which is "liblinphone", set from CMakeList.txt*/
NULL
};
@ -195,7 +199,7 @@ void linphone_logging_service_set_log_level(LinphoneLoggingService *log_service,
void linphone_logging_service_set_log_level_mask(LinphoneLoggingService *log_service, unsigned int mask) {
const char **domain;
for (domain=_linphone_logging_service_log_domains; *domain; domain++) {
bctbx_set_log_level_mask(*domain, _linphone_log_mask_to_bctbx_log_mask(mask));
bctbx_set_log_level_mask(*domain, (int)_linphone_log_mask_to_bctbx_log_mask(mask));
}
}
@ -236,10 +240,9 @@ void linphone_logging_service_cbs_unref(LinphoneLoggingServiceCbs *cbs) {
}
void linphone_logging_service_cbs_set_log_message_written(LinphoneLoggingServiceCbs *cbs, LinphoneLoggingServiceCbsLogMessageWrittenCb cb) {
/* We need to set the legacy log handler to NULL here
because LinphoneCore have a default log handler that dump
all messages into the standard output. */
because LinphoneCore have a default log handler that dump
all messages into the standard output. */
/*this function is moved here to make sure default log handler is only removed when user defined logging cbs is set*/
_linphone_core_set_log_handler(NULL);
cbs->message_event_cb = cb;
@ -253,6 +256,10 @@ void linphone_logging_service_cbs_set_user_data(LinphoneLoggingServiceCbs *cbs,
cbs->user_data = user_data;
}
void *linphone_logging_service_cbs_get_user_data(const LinphoneLoggingServiceCbs *cbs) {
return cbs->user_data;
}
BELLE_SIP_INSTANCIATE_VPTR(LinphoneLoggingServiceCbs, belle_sip_object_t,
NULL, // uninit
NULL, // clone

View file

@ -31,8 +31,8 @@ static xmlChar* convert_iso_to_utf8(const char *in) {
int ret, size, out_size, temp;
xmlCharEncodingHandlerPtr handler;
size = (int)strlen(in) + 1;
out_size = size * 2 - 1;
size = (int)strlen(in) + 1;
out_size = size * 2 - 1;
out = reinterpret_cast<xmlChar *>(ms_malloc((size_t)out_size));
if (out) {
@ -41,19 +41,19 @@ static xmlChar* convert_iso_to_utf8(const char *in) {
ms_free(out);
return NULL;
}
temp = size-1;
ret = handler->input(out, &out_size, (const xmlChar *)in, &temp);
if (ret < 0 || temp - size + 1) {
ms_free(out);
return NULL;
} else {
out = reinterpret_cast<xmlChar *>(ms_realloc(out, out_size + 1));
out = reinterpret_cast<xmlChar *>(ms_realloc(out, (size_t)out_size + 1));
out[out_size] = '\0';
}
}
return out;
}
}
struct _lpc2xml_context {
const LpConfig *lpc;
@ -131,7 +131,7 @@ static int processEntry(const char *section, const char *entry, xmlNode *node, l
}
lpc2xml_log(ctx, LPC2XML_MESSAGE, "Set %s|%s = %s", section, entry, content);
converted_content = convert_iso_to_utf8(content);
if (converted_content) {
// xmlNodeSetContent expects special characters to be escaped, xmlNodeAddContent doesn't (and escapes what needs to be)
xmlNodeSetContent(node, (const xmlChar *) "");
@ -142,7 +142,7 @@ static int processEntry(const char *section, const char *entry, xmlNode *node, l
xmlNodeSetContent(node, (const xmlChar *) "");
xmlNodeAddContent(node, (const xmlChar *) content);
}
if (lp_config_get_overwrite_flag_for_entry(ctx->lpc, section, entry) || lp_config_get_overwrite_flag_for_section(ctx->lpc, section)) {
xmlSetProp(node, (const xmlChar *)"overwrite", (const xmlChar *) "true");
}
@ -166,7 +166,7 @@ static void processSection_cb(const char *entry, struct __processSectionCtx *ctx
ctx->ret = 0;
return;
}
if (lp_config_get_skip_flag_for_entry(ctx->ctx->lpc, ctx->section, entry)) {
lpc2xml_log(ctx->ctx, LPC2XML_WARNING, "Skipped entry %s", entry);
ctx->ret = 0;
@ -208,13 +208,13 @@ static void processConfig_cb(const char *section, struct __processConfigCtx *ctx
if(ctx->ret == 0) {
xmlNode *node;
xmlAttr *name_attr;
if (lp_config_get_skip_flag_for_section(ctx->ctx->lpc, section)) {
lpc2xml_log(ctx->ctx, LPC2XML_WARNING, "Skipped section %s", section);
ctx->ret = 0;
return;
}
node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"section", NULL);
if(node == NULL) {
lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"section\" element");
@ -299,7 +299,7 @@ int lpc2xml_convert_file(lpc2xml_context* context, const char *filename) {
if(save_ctx != NULL) {
ret = internal_convert_lpc2xml(context);
if(ret == 0) {
ret = xmlSaveDoc(save_ctx, context->doc);
ret = (int)xmlSaveDoc(save_ctx, context->doc);
if(ret != 0) {
lpc2xml_log(context, LPC2XML_ERROR, "Can't save document");
lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer);
@ -322,7 +322,7 @@ int lpc2xml_convert_fd(lpc2xml_context* context, int fd) {
if(save_ctx != NULL) {
ret = internal_convert_lpc2xml(context);
if(ret == 0) {
ret = xmlSaveDoc(save_ctx, context->doc);
ret = (int)xmlSaveDoc(save_ctx, context->doc);
if(ret != 0) {
lpc2xml_log(context, LPC2XML_ERROR, "Can't save document");
lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer);
@ -346,7 +346,7 @@ int lpc2xml_convert_string(lpc2xml_context* context, char **content) {
if(save_ctx != NULL) {
ret = internal_convert_lpc2xml(context);
if(ret == 0) {
ret = xmlSaveDoc(save_ctx, context->doc);
ret = (int)xmlSaveDoc(save_ctx, context->doc);
if(ret != 0) {
lpc2xml_log(context, LPC2XML_ERROR, "Can't save document");
lpc2xml_log(context, LPC2XML_ERROR, "%s", context->errorBuffer);

View file

@ -24,7 +24,6 @@
#define MAX_LEN 16384
#include "private.h"
#include "bctoolbox/vfs.h"
#include "belle-sip/object.h"
#include "xml2lpc.h"
@ -61,6 +60,8 @@
#include "linphone/lpconfig.h"
#include "lpc2xml.h"
#include "c-wrapper/c-wrapper.h"
typedef struct _LpItem{
char *key;
char *value;
@ -647,7 +648,6 @@ bool_t linphone_config_get_range(const LpConfig *lpconfig, const char *section,
}
}
int linphone_config_get_int(const LpConfig *lpconfig,const char *section, const char *key, int default_value){
const char *str=linphone_config_get_string(lpconfig,section,key,NULL);
if (str!=NULL) {
@ -662,6 +662,16 @@ int linphone_config_get_int(const LpConfig *lpconfig,const char *section, const
else return default_value;
}
bool_t linphone_config_get_bool(const LpConfig *lpconfig, const char *section, const char *key, bool_t default_value) {
const char *str = linphone_config_get_string(lpconfig, section, key, NULL);
if (str != NULL) {
int ret = 0;
sscanf(str, "%i", &ret);
return ret != 0;
}
return default_value;
}
int64_t linphone_config_get_int64(const LpConfig *lpconfig,const char *section, const char *key, int64_t default_value){
const char *str=linphone_config_get_string(lpconfig,section,key,NULL);
if (str!=NULL) {
@ -774,6 +784,14 @@ void linphone_config_set_int(LpConfig *lpconfig,const char *section, const char
linphone_config_set_string(lpconfig,section,key,tmp);
}
void linphone_config_set_bool(LpConfig *lpconfig, const char *section, const char *key, bool_t value) {
if (value) {
linphone_config_set_int(lpconfig, section, key, 1);
} else {
linphone_config_set_int(lpconfig, section, key, 0);
}
}
void linphone_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value){
char tmp[30];
snprintf(tmp,sizeof(tmp),"0x%x",value);
@ -832,11 +850,11 @@ void linphone_config_set_skip_flag_for_section(LpConfig *lpconfig, const char *s
void lp_item_write(LpItem *item, LpConfig *lpconfig){
int ret =-1 ;
if (item->is_comment){
ret =bctbx_file_fprintf(lpconfig->pFile, 0, "%s\n",item->value);
ret = (int)bctbx_file_fprintf(lpconfig->pFile, 0, "%s\n",item->value);
}
else if (item->value && item->value[0] != '\0' ){
ret =bctbx_file_fprintf(lpconfig->pFile, 0, "%s=%s\n",item->key,item->value);
ret = (int)bctbx_file_fprintf(lpconfig->pFile, 0, "%s=%s\n",item->key,item->value);
}
else {
@ -1126,6 +1144,19 @@ const char** linphone_config_get_sections_names(LpConfig *lpconfig) {
return sections_names;
}
const bctbx_list_t * linphone_config_get_sections_names_list(LpConfig *lpconfig) {
const bctbx_list_t *sections = lpconfig->sections;
bctbx_list_t *sections_names = NULL;
int i;
for (i = 0; sections != NULL; sections = sections->next, i++) {
LpSection *section = (LpSection *)sections->data;
sections_names = bctbx_list_append(sections_names, section->name);
}
return sections_names;
}
char* linphone_config_dump_as_xml(const LpConfig *lpconfig) {
char *buffer;

View file

@ -1,950 +0,0 @@
/*
message_storage.c
Copyright (C) 2012 Belledonne Communications, Grenoble, France
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 "private.h"
#include "linphone/core.h"
#include "bctoolbox/charconv.h"
#ifdef SQLITE_STORAGE_ENABLED
#include "sqlite3.h"
#include <assert.h>
int _linphone_sqlite3_open(const char *db_file, sqlite3 **db) {
char* errmsg = NULL;
int ret;
int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
#if TARGET_OS_IPHONE
/* the secured filesystem of the iPHone doesn't allow writing while the app is in background mode, which is problematic.
* We workaround by asking that the open is made with no protection*/
flags |= SQLITE_OPEN_FILEPROTECTION_NONE;
#endif
/*since we plug our vfs into sqlite, we convert to UTF-8.
* On Windows, the filename has to be converted back to windows native charset.*/
char *utf8_filename = bctbx_locale_to_utf8(db_file);
ret = sqlite3_open_v2(utf8_filename, db, flags, LINPHONE_SQLITE3_VFS);
ms_free(utf8_filename);
if (ret != SQLITE_OK) return ret;
// Some platforms do not provide a way to create temporary files which are needed
// for transactions... so we work in memory only
// see http ://www.sqlite.org/compile.html#temp_store
ret = sqlite3_exec(*db, "PRAGMA temp_store=MEMORY", NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
ms_error("Cannot set sqlite3 temporary store to memory: %s.", errmsg);
sqlite3_free(errmsg);
}
/* the lines below have been disabled because they are likely an
* outdated hack */
#if 0 && TARGET_OS_IPHONE
ret = sqlite3_exec(*db, "PRAGMA journal_mode = OFF", NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
ms_error("Cannot set sqlite3 journal_mode to off: %s.", errmsg);
sqlite3_free(errmsg);
}
#endif
return ret;
}
#endif
#ifdef SQLITE_STORAGE_ENABLED
static LinphoneChatMessage * get_weak_message(LinphoneChatRoom *cr, unsigned int storage_id) {
LinphoneChatMessage *cm;
bctbx_list_t *item;
for (item = cr->weak_messages; item != NULL; item = bctbx_list_next(item)) {
cm = (LinphoneChatMessage *)bctbx_list_get_data(item);
if (linphone_chat_message_get_storage_id(cm) == storage_id)
return linphone_chat_message_ref(cm);
}
return NULL;
}
static ORTP_INLINE LinphoneChatMessage* get_transient_message(LinphoneChatRoom* cr, unsigned int storage_id){
bctbx_list_t* transients = cr->transient_messages;
LinphoneChatMessage* chat;
while( transients ){
chat = (LinphoneChatMessage*)transients->data;
if(chat->storage_id == storage_id){
return linphone_chat_message_ref(chat);
}
transients = transients->next;
}
return NULL;
}
/* DB layout:
* | 0 | storage_id
* | 1 | type
* | 2 | subtype
* | 3 | name
* | 4 | encoding
* | 5 | size
* | 6 | data (currently not stored)
* | 7 | key size
* | 8 | key
*/
// Callback for sql request when getting linphone content
static int callback_content(void *data, int argc, char **argv, char **colName) {
LinphoneChatMessage *message = (LinphoneChatMessage *)data;
if (message->file_transfer_information) {
linphone_content_unref(message->file_transfer_information);
message->file_transfer_information = NULL;
}
message->file_transfer_information = linphone_content_new();
if (argv[1]) linphone_content_set_type(message->file_transfer_information, argv[1]);
if (argv[2]) linphone_content_set_subtype(message->file_transfer_information, argv[2]);
if (argv[3]) linphone_content_set_name(message->file_transfer_information, argv[3]);
if (argv[4]) linphone_content_set_encoding(message->file_transfer_information, argv[4]);
linphone_content_set_size(message->file_transfer_information, (size_t)atoi(argv[5]));
if (argv[8]) linphone_content_set_key(message->file_transfer_information, argv[8], (size_t)atol(argv[7]));
return 0;
}
static void fetch_content_from_database(sqlite3 *db, LinphoneChatMessage *message, int content_id) {
char* errmsg = NULL;
int ret;
char * buf;
buf = sqlite3_mprintf("SELECT * FROM content WHERE id = %i", content_id);
ret = sqlite3_exec(db, buf, callback_content, message, &errmsg);
if (ret != SQLITE_OK) {
ms_error("Error in creation: %s.", errmsg);
sqlite3_free(errmsg);
}
sqlite3_free(buf);
}
// Called when fetching all conversations from database
static int callback_all(void *data, int argc, char **argv, char **colName){
LinphoneCore* lc = (LinphoneCore*) data;
char* address = argv[0];
LinphoneAddress *addr = linphone_address_new(address);
if (addr){
linphone_core_get_chat_room(lc, addr);
linphone_address_unref(addr);
}
return 0;
}
/* DB layout:
* | 0 | storage_id
* | 1 | localContact
* | 2 | remoteContact
* | 3 | direction flag (LinphoneChatMessageDir)
* | 4 | message (text content of the message)
* | 5 | time (unused now, used to be string-based timestamp, replaced by the utc timestamp)
* | 6 | read flag (no longer used, replaced by the LinphoneChatMessageStateDisplayed state)
* | 7 | status (LinphoneChatMessageState)
* | 8 | external body url (deprecated file transfer system)
* | 9 | utc timestamp
* | 10 | app data text
* | 11 | linphone content id (LinphoneContent describing a file transfer)
* | 12 | message id (used for IMDN)
* | 13 | content type (of the message field [must be text representable])
* | 14 | secured flag
*/
static int create_chat_message(void *data, int argc, char **argv, char **colName){
LinphoneChatRoom *cr = (LinphoneChatRoom *)data;
unsigned int storage_id = (unsigned int)atoi(argv[0]);
LinphoneChatMessage* new_message;
/* Check if the message exists in the weak messages list, in which case we should return that one. */
new_message = get_weak_message(cr, storage_id);
if (new_message == NULL) {
/* Check if the message exists in the transient list, in which case we should return that one. */
new_message = get_transient_message(cr, storage_id);
}
if (new_message == NULL) {
new_message = linphone_chat_room_create_message_without_conversion(cr, argv[4]);
if(atoi(argv[3])==LinphoneChatMessageIncoming){
new_message->dir=LinphoneChatMessageIncoming;
linphone_chat_message_set_from(new_message,linphone_chat_room_get_peer_address(cr));
new_message->to = NULL; /*will be filled at the end */
} else {
new_message->dir=LinphoneChatMessageOutgoing;
new_message->from = NULL; /*will be filled at the end */
linphone_chat_message_set_to(new_message,linphone_chat_room_get_peer_address(cr));
}
new_message->time = (time_t)atol(argv[9]);
new_message->is_read=atoi(argv[6]);
new_message->state=static_cast<LinphoneChatMessageState>(atoi(argv[7]));
new_message->storage_id=storage_id;
new_message->external_body_url= ms_strdup(argv[8]);
new_message->appdata = ms_strdup(argv[10]);
new_message->message_id = ms_strdup(argv[12]);
linphone_chat_message_set_content_type(new_message, argv[13]);
new_message->is_secured = (bool_t)atoi(argv[14]);
if (argv[11] != NULL) {
int id = atoi(argv[11]);
if (id >= 0) {
fetch_content_from_database(cr->lc->db, new_message, id);
}
}
/* Fix content type for old messages that were stored without it */
if (new_message->content_type == NULL) {
if (new_message->file_transfer_information != NULL) {
new_message->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml");
} else if (new_message->external_body_url != NULL) {
new_message->content_type = ms_strdup("message/external-body");
} else {
new_message->content_type = ms_strdup("text/plain");
}
}
/* Add the new message to the weak messages list. */
linphone_chat_room_add_weak_message(cr, new_message);
}
cr->messages_hist=bctbx_list_prepend(cr->messages_hist,new_message);
return 0;
}
void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,create_chat_message,cr,&errmsg);
if(ret != SQLITE_OK) {
ms_error("Error in creation: %s.", errmsg);
sqlite3_free(errmsg);
}
}
int linphone_sql_request(sqlite3* db,const char *stmt){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_error("linphone_sql_request: statement %s -> error sqlite3_exec(): %s.", stmt, errmsg);
sqlite3_free(errmsg);
}
return ret;
}
// Process the request to fetch all chat contacts
void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg);
if(ret != SQLITE_OK) {
ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.", errmsg);
sqlite3_free(errmsg);
}
}
static int linphone_chat_message_store_content(LinphoneChatMessage *msg) {
LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room);
int id = -1;
if (lc->db) {
LinphoneContent *content = msg->file_transfer_information;
char *buf = sqlite3_mprintf("INSERT INTO content VALUES(NULL,%Q,%Q,%Q,%Q,%i,%Q,%lld,%Q);",
linphone_content_get_type(content),
linphone_content_get_subtype(content),
linphone_content_get_name(content),
linphone_content_get_encoding(content),
linphone_content_get_size(content),
NULL,
(int64_t)linphone_content_get_key_size(content),
linphone_content_get_key(content)
);
linphone_sql_request(lc->db, buf);
sqlite3_free(buf);
id = (unsigned int) sqlite3_last_insert_rowid (lc->db);
}
return id;
}
unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){
LinphoneCore *lc=linphone_chat_room_get_core(msg->chat_room);
int id = 0;
if (lc->db){
int content_id = -1;
char *peer;
char *local_contact;
char *buf;
if (msg->file_transfer_information) {
content_id = linphone_chat_message_store_content(msg);
}
peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room));
local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg));
buf = sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%lld,%Q,%i,%Q,%Q,%i);",
local_contact,
peer,
msg->dir,
msg->message,
"-1", /* use UTC field now */
FALSE, /* use state == LinphoneChatMessageStateDisplayed now */
msg->state,
msg->external_body_url,
(int64_t)msg->time,
msg->appdata,
content_id,
msg->message_id,
msg->content_type,
(int)msg->is_secured
);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(local_contact);
ms_free(peer);
id = (unsigned int) sqlite3_last_insert_rowid (lc->db);
}
return id;
}
void linphone_chat_message_store_update(LinphoneChatMessage *msg) {
LinphoneCore *lc = linphone_chat_room_get_core(msg->chat_room);
if (lc->db) {
char *peer;
char *local_contact;
char *buf;
peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room));
local_contact = linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg));
buf = sqlite3_mprintf("UPDATE history SET"
" localContact = %Q,"
" remoteContact = %Q,"
" message = %Q,"
" status = %i,"
" appdata = %Q,"
" messageId = %Q,"
" content_type = %Q"
" WHERE (id = %u);",
local_contact,
peer,
msg->message,
msg->state,
msg->appdata,
msg->message_id,
msg->content_type,
msg->storage_id
);
linphone_sql_request(lc->db, buf);
sqlite3_free(buf);
ms_free(local_contact);
ms_free(peer);
}
}
void linphone_chat_message_store_state(LinphoneChatMessage *msg){
LinphoneCore *lc=msg->chat_room->lc;
if (lc->db){
char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (id = %u);",
msg->state,msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
}
void linphone_chat_message_store_appdata(LinphoneChatMessage* msg){
LinphoneCore *lc=msg->chat_room->lc;
if (lc->db){
char *buf=sqlite3_mprintf("UPDATE history SET appdata=%Q WHERE id=%u;",
msg->appdata,msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
}
void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
LinphoneCore *lc=linphone_chat_room_get_core(cr);
bctbx_list_t *item;
char *peer;
char *buf;
if (lc->db==NULL) return ;
// optimization: do not modify the database if no message is marked as unread
if(linphone_chat_room_get_unread_messages_count(cr) == 0) return;
peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND direction = %i AND status != %i", peer, LinphoneChatMessageIncoming, LinphoneChatMessageStateDisplayed);
linphone_sql_request_message(lc->db, buf, cr);
sqlite3_free(buf);
for (item = cr->messages_hist; item != NULL; item = bctbx_list_next(item)) {
LinphoneChatMessage *cm = (LinphoneChatMessage *)bctbx_list_get_data(item);
linphone_chat_message_send_display_notification(cm);
}
bctbx_list_free_with_data(cr->messages_hist, (bctbx_list_free_func)linphone_chat_message_unref);
cr->messages_hist = NULL;
buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE remoteContact=%Q AND direction=%i;",
LinphoneChatMessageStateDisplayed, peer, LinphoneChatMessageIncoming);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
if (cr->pending_message) {
linphone_chat_message_set_state(cr->pending_message, LinphoneChatMessageStateDisplayed);
linphone_chat_message_send_display_notification(cr->pending_message);
}
cr->unread_count = 0;
}
void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
LinphoneCore *lc=linphone_chat_room_get_core(cr);
char *buf;
if (lc->db==NULL) return ;
buf=sqlite3_mprintf("UPDATE history SET url=%Q WHERE id=%u;",msg->external_body_url,msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
}
static int linphone_chat_room_get_messages_count(LinphoneChatRoom *cr, bool_t unread_only){
LinphoneCore *lc=linphone_chat_room_get_core(cr);
int numrows=0;
char *peer;
char *buf;
char *option = NULL;
sqlite3_stmt *selectStatement;
int returnValue;
if (lc->db==NULL) return 0;
// optimization: do not read database if the count is already available in memory
if(unread_only && cr->unread_count >= 0) return cr->unread_count;
peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
if (unread_only) {
option = bctbx_strdup_printf("AND status!=%i AND direction=%i", LinphoneChatMessageStateDisplayed, LinphoneChatMessageIncoming);
}
buf=sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q %s;",peer,unread_only?option:"");
returnValue = sqlite3_prepare_v2(lc->db,buf,-1,&selectStatement,NULL);
if (returnValue == SQLITE_OK){
if(sqlite3_step(selectStatement) == SQLITE_ROW){
numrows= sqlite3_column_int(selectStatement, 0);
}
}
sqlite3_finalize(selectStatement);
sqlite3_free(buf);
ms_free(peer);
/* no need to test the sign of cr->unread_count here
* because it has been tested above */
if(unread_only) {
cr->unread_count = numrows;
if (option) bctbx_free(option);
}
return numrows;
}
int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){
return linphone_chat_room_get_messages_count(cr, TRUE);
}
int linphone_chat_room_get_history_size(LinphoneChatRoom *cr){
return linphone_chat_room_get_messages_count(cr, FALSE);
}
void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
LinphoneCore *lc=cr->lc;
char *buf;
if (lc->db==NULL) return ;
buf=sqlite3_mprintf("DELETE FROM history WHERE id = %u;", msg->storage_id);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
/* Invalidate unread_count when we modify the database, so that next
time we need it it will be recomputed from latest database state */
cr->unread_count = -1;
}
void linphone_chat_room_delete_history(LinphoneChatRoom *cr){
LinphoneCore *lc=cr->lc;
char *peer;
char *buf;
if (lc->db==NULL) return ;
peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
buf=sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;",peer);
linphone_sql_request(lc->db,buf);
sqlite3_free(buf);
ms_free(peer);
if(cr->unread_count > 0) cr->unread_count = 0;
}
bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int startm, int endm){
LinphoneCore *lc=linphone_chat_room_get_core(cr);
bctbx_list_t *ret;
char *buf,*buf2;
char *peer;
uint64_t begin,end;
int buf_max_size = 512;
if (lc->db==NULL) return NULL;
peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
cr->messages_hist = NULL;
/*since we want to append query parameters depending on arguments given, we use malloc instead of sqlite3_mprintf*/
buf=reinterpret_cast<char *>(ms_malloc(buf_max_size));
buf=sqlite3_snprintf(buf_max_size-1,buf,"SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC",peer);
if (startm<0) startm=0;
if ((endm>0&&endm>=startm) || (startm == 0 && endm == 0) ){
buf2=ms_strdup_printf("%s LIMIT %i ",buf,endm+1-startm);
ms_free(buf);
buf = buf2;
}else if(startm>0){
ms_message("%s(): end is lower than start (%d < %d). Assuming no end limit.",__FUNCTION__,endm,startm);
buf2=ms_strdup_printf("%s LIMIT -1",buf);
ms_free(buf);
buf = buf2;
}
if (startm>0){
buf2=ms_strdup_printf("%s OFFSET %i ",buf,startm);
ms_free(buf);
buf = buf2;
}
begin=ortp_get_cur_time_ms();
linphone_sql_request_message(lc->db,buf,cr);
end=ortp_get_cur_time_ms();
if (endm+1-startm > 1) {
//display message only if at least 2 messages are loaded
ms_message("%s(): completed in %i ms",__FUNCTION__, (int)(end-begin));
}
ms_free(buf);
if (cr->messages_hist) {
//fill local addr with core identity instead of per message
LinphoneAddress* local_addr = linphone_address_new(linphone_core_get_identity(cr->lc));
bctbx_list_t* it = cr->messages_hist;
while (it) {
LinphoneChatMessage* msg = reinterpret_cast<LinphoneChatMessage *>(it->data);
if (msg->dir == LinphoneChatMessageOutgoing) {
if (msg->from != NULL) linphone_address_unref(msg->from);
msg->from = linphone_address_ref(local_addr);
} else {
msg->to = linphone_address_ref(local_addr);
}
it = it->next;
}
linphone_address_unref(local_addr);
}
ret=cr->messages_hist;
cr->messages_hist=NULL;
ms_free(peer);
return ret;
}
bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){
return linphone_chat_room_get_history_range(cr, 0, nb_message-1);
}
bctbx_list_t* linphone_chat_room_find_messages(LinphoneChatRoom *cr, const char *message_id) {
LinphoneCore *lc = linphone_chat_room_get_core(cr);
char *buf;
char *peer;
bctbx_list_t* messages;
if (lc->db == NULL) return NULL;
peer = linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr));
cr->messages_hist = NULL;
buf = sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q AND messageId = %Q", peer, message_id);
linphone_sql_request_message(lc->db, buf, cr);
sqlite3_free(buf);
ms_free(peer);
messages = cr->messages_hist;
cr->messages_hist = NULL;
return messages;
}
LinphoneChatMessage * linphone_chat_room_find_message_with_dir(LinphoneChatRoom *cr, const char *message_id, LinphoneChatMessageDir dir) {
bctbx_list_t* messages = linphone_chat_room_find_messages(cr, message_id);
bctbx_list_t* it;
LinphoneChatMessage *ret = NULL;
for (it = messages; it != NULL; it = it->next) {
LinphoneChatMessage * cm = (LinphoneChatMessage*)it->data;
if (cm->dir == dir) {
linphone_chat_message_ref(cm);
ret = cm;
break;
}
}
if (messages)
bctbx_list_free_with_data(messages, (bctbx_list_free_func)linphone_chat_message_unref);
return ret;
}
LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id) {
bctbx_list_t* messages = linphone_chat_room_find_messages(cr, message_id);
LinphoneChatMessage *cm = NULL;
if (messages) {
cm = (LinphoneChatMessage *)bctbx_list_nth_data(messages, 0);
linphone_chat_message_ref(cm);
bctbx_list_free_with_data(messages, (bctbx_list_free_func)linphone_chat_message_unref);
}
return cm;
}
static void linphone_create_history_table(sqlite3* db){
char* errmsg=NULL;
int ret;
ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS history ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"localContact TEXT NOT NULL,"
"remoteContact TEXT NOT NULL,"
"direction INTEGER,"
"message TEXT,"
"time TEXT NOT NULL,"
"read INTEGER,"
"status INTEGER"
");",
0,0,&errmsg);
if(ret != SQLITE_OK) {
ms_error("Error in creation: %s.\n", errmsg);
sqlite3_free(errmsg);
}
}
static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
static time_t parse_time_from_db( const char* time ){
/* messages used to be stored in the DB by using string-based time */
struct tm ret={0};
char tmp1[80]={0};
char tmp2[80]={0};
int i,j;
time_t parsed = 0;
if( sscanf(time,"%3c %3c%d%d:%d:%d %d",tmp1,tmp2,&ret.tm_mday,
&ret.tm_hour,&ret.tm_min,&ret.tm_sec,&ret.tm_year) == 7 ){
ret.tm_year-=1900;
for(i=0;i<7;i++) {
if(strcmp(tmp1,days[i])==0) ret.tm_wday=i;
}
for(j=0;j<12;j++) {
if(strcmp(tmp2,months[j])==0) ret.tm_mon=j;
}
ret.tm_isdst=-1;
parsed = mktime(&ret);
}
return parsed;
}
static int migrate_messages_timestamp(void* data,int argc, char** argv, char** column_names) {
time_t new_time = parse_time_from_db(argv[1]);
if( new_time ){
/* replace 'time' by -1 and set 'utc' to the timestamp */
char *buf = sqlite3_mprintf("UPDATE history SET utc=%lld,time='-1' WHERE id=%i;", (int64_t)new_time, atoi(argv[0]));
if( buf) {
linphone_sql_request((sqlite3*)data, buf);
sqlite3_free(buf);
}
} else {
ms_warning("Cannot parse time %s from id %s", argv[1], argv[0]);
}
return 0;
}
static void linphone_migrate_timestamps(sqlite3* db){
int ret;
char* errmsg = NULL;
uint64_t begin=ortp_get_cur_time_ms();
linphone_sql_request(db,"BEGIN TRANSACTION");
ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1';", migrate_messages_timestamp, db, &errmsg);
if( ret != SQLITE_OK ){
ms_warning("Error migrating outgoing messages: %s.\n", errmsg);
sqlite3_free(errmsg);
linphone_sql_request(db, "ROLLBACK");
} else {
uint64_t end;
linphone_sql_request(db, "COMMIT");
end=ortp_get_cur_time_ms();
ms_message("Migrated message timestamps to UTC in %lu ms",(unsigned long)(end-begin));
}
}
static void linphone_update_history_table(sqlite3* db) {
char* errmsg=NULL;
char *buf;
int ret;
// for image url storage
ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_message("Table already up to date: %s.", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table history updated successfully for URL.");
}
// for UTC timestamp storage
ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN utc INTEGER;", NULL,NULL,&errmsg);
if( ret != SQLITE_OK ){
ms_message("Table already up to date: %s.", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table history updated successfully for UTC.");
// migrate from old text-based timestamps to unix time-based timestamps
linphone_migrate_timestamps(db);
}
// new field for app-specific storage
ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN appdata TEXT;",NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_message("Table already up to date: %s.", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table history updated successfully for app-specific data.");
}
// new field for linphone content storage
ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN content INTEGER;",NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_message("Table already up to date: %s.", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table history updated successfully for content data.");
ret = sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS content ("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"type TEXT,"
"subtype TEXT,"
"name TEXT,"
"encoding TEXT,"
"size INTEGER,"
"data BLOB"
");",
0,0,&errmsg);
if(ret != SQLITE_OK) {
ms_error("Error in creation: %s.\n", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table content successfully created.");
}
}
// new fields for content key storage when using lime
ret=sqlite3_exec(db,"ALTER TABLE content ADD COLUMN key_size INTEGER;",NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_message("Table already up to date: %s.", errmsg);
sqlite3_free(errmsg);
} else {
ret=sqlite3_exec(db,"ALTER TABLE content ADD COLUMN key TEXT;",NULL,NULL,&errmsg);
if(ret != SQLITE_OK) {
ms_message("Table already up to date: %s.", errmsg);
sqlite3_free(errmsg);
} else {
ms_debug("Table history content successfully for lime key storage data.");
}
}
// new field for message_id
ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN messageId TEXT;", NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
ms_message("Table already up to date: %s", errmsg);
sqlite3_free(errmsg);
} else {
ms_message("Table history updated successfully for messageId data.");
}
// Convert is_read to LinphoneChatMessageStateDisplayed
buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE read=1 AND direction=%i;", LinphoneChatMessageStateDisplayed, LinphoneChatMessageIncoming);
linphone_sql_request(db, buf);
sqlite3_free(buf);
/* New field for content type */
ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN content_type TEXT;", NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
ms_message("Table already up to date: %s", errmsg);
sqlite3_free(errmsg);
} else {
ms_message("Table history updated successfully for content_type data.");
}
// new field for secured flag
ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN is_secured INTEGER DEFAULT 0;", NULL, NULL, &errmsg);
if (ret != SQLITE_OK) {
ms_message("Table already up to date: %s", errmsg);
sqlite3_free(errmsg);
} else {
ms_message("Table history updated successfully for is_secured data.");
}
}
static void linphone_fix_outgoing_messages_state(sqlite3* db) {
/* Convert Idle and InProgress states of outgoing messages to NotDelivered */
char *buf = sqlite3_mprintf("UPDATE history SET status=%i WHERE direction=%i AND (status=%i OR status=%i);",
LinphoneChatMessageStateNotDelivered, LinphoneChatMessageOutgoing, LinphoneChatMessageStateIdle, LinphoneChatMessageStateInProgress);
linphone_sql_request(db, buf);
sqlite3_free(buf);
}
void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) {
char *buf;
if (lc->db==NULL) return;
buf=sqlite3_mprintf("SELECT remoteContact FROM history GROUP BY remoteContact;");
linphone_sql_request_all(lc->db,buf,lc);
sqlite3_free(buf);
}
static void _linphone_message_storage_profile(void*data,const char*statement, sqlite3_uint64 duration){
ms_warning("SQL statement '%s' took %llu microseconds", statement, (unsigned long long)(duration / 1000LL) );
}
static void linphone_message_storage_activate_debug(sqlite3* db, bool_t debug){
if( debug ){
sqlite3_profile(db, _linphone_message_storage_profile, NULL );
} else {
sqlite3_profile(db, NULL, NULL );
}
}
void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug){
lc->debug_storage = debug;
if( lc->db ){
linphone_message_storage_activate_debug(lc->db, debug);
}
}
void linphone_core_message_storage_init(LinphoneCore *lc){
int ret;
const char *errmsg;
sqlite3 *db = NULL;
linphone_core_message_storage_close(lc);
ret=_linphone_sqlite3_open(lc->chat_db_file,&db);
if(ret != SQLITE_OK) {
errmsg=sqlite3_errmsg(db);
ms_error("Error in the opening: %s.\n", errmsg);
sqlite3_close(db);
return;
}
linphone_message_storage_activate_debug(db, lc->debug_storage);
linphone_create_history_table(db);
linphone_update_history_table(db);
linphone_fix_outgoing_messages_state(db);
lc->db=db;
// Create a chatroom for each contact in the chat history
linphone_message_storage_init_chat_rooms(lc);
}
void linphone_core_message_storage_close(LinphoneCore *lc){
if (lc->db){
sqlite3_close(lc->db);
lc->db=NULL;
}
}
#else
unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){
return 0;
}
void linphone_chat_message_store_state(LinphoneChatMessage *cr){
}
void linphone_chat_message_store_appdata(LinphoneChatMessage *msg){
}
void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){
}
bctbx_list_t *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){
return NULL;
}
bctbx_list_t *linphone_chat_room_get_history_range(LinphoneChatRoom *cr, int begin, int end){
return NULL;
}
LinphoneChatMessage * linphone_chat_room_find_message(LinphoneChatRoom *cr, const char *message_id) {
return NULL;
}
void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
}
void linphone_chat_room_delete_history(LinphoneChatRoom *cr){
}
void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) {
}
void linphone_core_message_storage_init(LinphoneCore *lc){
}
void linphone_core_message_storage_close(LinphoneCore *lc){
}
void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) {
}
int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){
return 0;
}
int linphone_chat_room_get_history_size(LinphoneChatRoom *cr){
return 0;
}
void linphone_chat_message_store_update(LinphoneChatMessage *msg){
}
LinphoneChatMessage * linphone_chat_room_find_message_with_dir(LinphoneChatRoom *cr, const char *message_id, LinphoneChatMessageDir dir) {
return NULL;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -18,8 +18,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "linphone/core.h"
#include "private.h"
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
static LinphoneNatPolicy * _linphone_nat_policy_new_with_ref(LinphoneCore *lc, const char *ref) {
LinphoneNatPolicy *policy = belle_sip_object_new(LinphoneNatPolicy);
@ -163,12 +166,7 @@ bool_t linphone_nat_policy_upnp_enabled(const LinphoneNatPolicy *policy) {
void linphone_nat_policy_enable_upnp(LinphoneNatPolicy *policy, bool_t enable) {
policy->upnp_enabled = enable;
if (enable) {
#ifdef BUILD_UPNP
policy->stun_enabled = policy->turn_enabled = policy->ice_enabled = FALSE;
ms_warning("Enabling uPnP NAT policy has disabled any other previously enabled policies");
#else
ms_warning("Cannot enable the uPnP NAT policy because the uPnP support is not compiled in");
#endif
ms_warning("uPnP NAT policy is no longer supported");
}
}
@ -187,6 +185,17 @@ void linphone_nat_policy_set_stun_server(LinphoneNatPolicy *policy, const char *
if (new_stun_server != NULL) {
policy->stun_server = new_stun_server;
}
if (policy->stun_addrinfo) {
bctbx_freeaddrinfo(policy->stun_addrinfo);
policy->stun_addrinfo = NULL;
}
if (policy->stun_resolver_context){
belle_sip_resolver_context_cancel(policy->stun_resolver_context);
belle_sip_object_unref(policy->stun_resolver_context);
policy->stun_resolver_context = NULL;
}
linphone_nat_policy_resolve_stun_server(policy);
}
const char * linphone_nat_policy_get_stun_server_username(const LinphoneNatPolicy *policy) {
@ -227,7 +236,7 @@ void linphone_nat_policy_resolve_stun_server(LinphoneNatPolicy *policy) {
if (linphone_nat_policy_stun_server_activated(policy) && (policy->lc->sal != NULL) && !policy->stun_resolver_context) {
char host[NI_MAXHOST];
int port = 3478;
int port = 0;
linphone_parse_host_port(policy->stun_server, host, sizeof(host), &port);
if (linphone_nat_policy_turn_enabled(policy)) service = "turn";
else if (linphone_nat_policy_stun_enabled(policy)) service = "stun";
@ -235,7 +244,12 @@ void linphone_nat_policy_resolve_stun_server(LinphoneNatPolicy *policy) {
int family = AF_INET;
if (linphone_core_ipv6_enabled(policy->lc) == TRUE) family = AF_INET6;
ms_message("Starting stun server resolution [%s]", host);
policy->stun_resolver_context = sal_resolve(policy->lc->sal, service, "udp", host, port, family, stun_server_resolved, policy);
if (port == 0) {
port = 3478;
policy->stun_resolver_context = policy->lc->sal->resolve(service, "udp", host, port, family, stun_server_resolved, policy);
} else {
policy->stun_resolver_context = policy->lc->sal->resolveA(host, port, family, stun_server_resolved, policy);
}
if (policy->stun_resolver_context) belle_sip_object_ref(policy->stun_resolver_context);
}
}
@ -257,7 +271,7 @@ const struct addrinfo * linphone_nat_policy_get_stun_server_addrinfo(LinphoneNat
int wait_limit = 1000;
linphone_nat_policy_resolve_stun_server(policy);
while ((policy->stun_addrinfo == NULL) && (policy->stun_resolver_context != NULL) && (wait_ms < wait_limit)) {
sal_iterate(policy->lc->sal);
policy->lc->sal->iterate();
ms_usleep(50000);
wait_ms += 50;
}
@ -279,7 +293,7 @@ LinphoneNatPolicy * linphone_config_create_nat_policy_from_section(const Linphon
policy = _linphone_nat_policy_new_with_ref(NULL, config_ref);
else
policy = linphone_nat_policy_new(NULL);
if (server != NULL) linphone_nat_policy_set_stun_server(policy, server);
if (username != NULL) linphone_nat_policy_set_stun_server_username(policy, username);
if (l != NULL) {
@ -303,7 +317,7 @@ LinphoneNatPolicy * linphone_core_create_nat_policy_from_config(LinphoneCore *lc
char *section;
int index;
bool_t finished = FALSE;
for (index = 0; finished != TRUE; index++) {
section = belle_sip_strdup_printf("nat_policy_%i", index);
if (lp_config_has_section(config, section)) {
@ -318,3 +332,7 @@ LinphoneNatPolicy * linphone_core_create_nat_policy_from_config(LinphoneCore *lc
}
return policy;
}
LinphoneCore *linphone_nat_policy_get_core(const LinphoneNatPolicy *policy) {
return policy->lc;
}

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