forked from mirrors/linphone-iphone
Merge branch 'dev_refactor_cpp'
This commit is contained in:
commit
81688335c6
916 changed files with 113612 additions and 114940 deletions
107
CMakeLists.txt
107
CMakeLists.txt
|
|
@ -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()
|
||||
|
|
|
|||
46
README.md
46
README.md
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
@ -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})
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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){
|
||||
|
|
|
|||
|
|
@ -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 **************************/
|
||||
|
|
|
|||
201
coreapi/account_creator_private.h
Normal file
201
coreapi/account_creator_private.h
Normal 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_
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
1610
coreapi/callbacks.c
1610
coreapi/callbacks.c
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
1786
coreapi/chat.c
1786
coreapi/chat.c
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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
35
coreapi/core_private.h
Normal 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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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--){
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
202
coreapi/event.c
202
coreapi/event.c
|
|
@ -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
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
183
coreapi/friend.c
183
coreapi/friend.c
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -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 ------------------------------------------
|
||||
|
||||
|
|
|
|||
39
coreapi/help/doc/sphinx/enum_page.mustache
Normal file
39
coreapi/help/doc/sphinx/enum_page.mustache
Normal 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}}
|
||||
|
|
@ -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}}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
4
coreapi/help/doc/sphinx/guides/authentication.rst
Normal file
4
coreapi/help/doc/sphinx/guides/authentication.rst
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Managing authentication: userid and passwords
|
||||
=============================================
|
||||
|
||||
|
||||
57
coreapi/help/doc/sphinx/guides/buddy_list.rst
Normal file
57
coreapi/help/doc/sphinx/guides/buddy_list.rst
Normal 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"
|
||||
9
coreapi/help/doc/sphinx/guides/call_control.rst
Normal file
9
coreapi/help/doc/sphinx/guides/call_control.rst
Normal 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.
|
||||
2
coreapi/help/doc/sphinx/guides/call_logs.rst
Normal file
2
coreapi/help/doc/sphinx/guides/call_logs.rst
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Managing call logs
|
||||
==================
|
||||
4
coreapi/help/doc/sphinx/guides/call_misc.rst
Normal file
4
coreapi/help/doc/sphinx/guides/call_misc.rst
Normal 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.
|
||||
28
coreapi/help/doc/sphinx/guides/chatroom.rst
Normal file
28
coreapi/help/doc/sphinx/guides/chatroom.rst
Normal 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.
|
||||
|
||||
21
coreapi/help/doc/sphinx/guides/conferencing.rst
Normal file
21
coreapi/help/doc/sphinx/guides/conferencing.rst
Normal 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.
|
||||
4
coreapi/help/doc/sphinx/guides/event_api.rst
Normal file
4
coreapi/help/doc/sphinx/guides/event_api.rst
Normal 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.
|
||||
4
coreapi/help/doc/sphinx/guides/initializing.rst
Normal file
4
coreapi/help/doc/sphinx/guides/initializing.rst
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Initializing liblinphone
|
||||
========================
|
||||
|
||||
|
||||
285
coreapi/help/doc/sphinx/guides/ios_portability.rst
Normal file
285
coreapi/help/doc/sphinx/guides/ios_portability.rst
Normal 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
|
||||
4
coreapi/help/doc/sphinx/guides/linphone_address.rst
Normal file
4
coreapi/help/doc/sphinx/guides/linphone_address.rst
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
SIP address parser API
|
||||
======================
|
||||
|
||||
This api is useful for manipulating SIP addresses ('from' or 'to' headers).
|
||||
11
coreapi/help/doc/sphinx/guides/media_parameters.rst
Normal file
11
coreapi/help/doc/sphinx/guides/media_parameters.rst
Normal 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.
|
||||
3
coreapi/help/doc/sphinx/guides/misc.rst
Normal file
3
coreapi/help/doc/sphinx/guides/misc.rst
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Miscenalleous: logs, version strings, config storage
|
||||
====================================================
|
||||
|
||||
2
coreapi/help/doc/sphinx/guides/network_parameters.rst
Normal file
2
coreapi/help/doc/sphinx/guides/network_parameters.rst
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Controlling network parameters (ports, mtu…)
|
||||
============================================
|
||||
76
coreapi/help/doc/sphinx/guides/proxies.rst
Normal file
76
coreapi/help/doc/sphinx/guides/proxies.rst
Normal 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.
|
||||
|
||||
70
coreapi/help/doc/sphinx/index.rst
Normal file
70
coreapi/help/doc/sphinx/index.rst
Normal 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
|
||||
|
|
@ -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}}
|
||||
|
|
|
|||
BIN
coreapi/help/doc/sphinx/logo.png
Normal file
BIN
coreapi/help/doc/sphinx/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
106
coreapi/help/doc/sphinx/samples/samples.rst
Normal file
106
coreapi/help/doc/sphinx/samples/samples.rst
Normal 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
|
||||
|
||||
|
|
@ -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`
|
||||
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
236
coreapi/lime.c
236
coreapi/lime.c
|
|
@ -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(¤tTimeSpec);
|
||||
if (validityTimeSpec.tv_sec == 0 || bctbx_timespec_compare(¤tTimeSpec, &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(¤tTime);
|
||||
bctbx_timespec_add(¤tTime, validityTimeSpan);
|
||||
bctbx_timespec_add(¤tTime, (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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
1036
coreapi/misc.c
1036
coreapi/misc.c
File diff suppressed because it is too large
Load diff
|
|
@ -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
Loading…
Add table
Reference in a new issue