forked from mirrors/linphone-iphone
Merge remote-tracking branch 'linphone/master'
audiostream stats functionnality is broken now, it needs to be re-implemented from linphone/master branch first. Conflicts: configure.ac coreapi/linphonecall.c coreapi/private.h
This commit is contained in:
commit
c225486a16
204 changed files with 23076 additions and 9794 deletions
|
|
@ -22,12 +22,15 @@
|
|||
<folderInfo id="0.2079208171." name="/" resourcePath="">
|
||||
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.2084203071" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
|
||||
<targetPlatform binaryParser="org.eclipse.cdt.core.MachO64;org.eclipse.cdt.core.ELF" id="org.eclipse.cdt.build.core.prefbase.toolchain.2084203071.81924294" name=""/>
|
||||
<builder arguments="-j4 CFLAGS="-g -Wall -Qunused-arguments" CXXFLAGS="-g"" command="make" id="org.eclipse.cdt.build.core.settings.default.builder.731584538" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
|
||||
<builder arguments="-j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g"" autoBuildTarget="all" cleanBuildTarget="clean" command="make" enableAutoBuild="false" enableCleanBuild="true" enabledIncrementalBuild="true" id="org.eclipse.cdt.build.core.settings.default.builder.731584538" incrementalBuildTarget="all" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" parallelBuildOn="false" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
|
||||
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.1252970003" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
|
||||
<tool id="org.eclipse.cdt.build.core.settings.holder.1371414073" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
|
||||
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.306286573" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
|
||||
</tool>
|
||||
<tool id="org.eclipse.cdt.build.core.settings.holder.391709798" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
|
||||
<option id="org.eclipse.cdt.build.core.settings.holder.incpaths.295320884" name="Include Paths" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value="/Users/jehanmonnier/workspaces/workspace-macosx/opt/include"/>
|
||||
</option>
|
||||
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1702094818" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
|
||||
</tool>
|
||||
<tool id="org.eclipse.cdt.build.core.settings.holder.754828354" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
|
||||
|
|
@ -39,6 +42,7 @@
|
|||
<sourceEntries>
|
||||
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="coreapi"/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="gtk"/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="include"/>
|
||||
<entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name="tester"/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -41,6 +41,7 @@ Specfile
|
|||
.anjuta_sym_db.db
|
||||
gtk-glade/version_date.h
|
||||
share/linphone.desktop
|
||||
share/audio-assistant.desktop
|
||||
Debug/
|
||||
build/macos/Info-linphone.plist
|
||||
coreapi/help/Doxyfile
|
||||
|
|
@ -72,4 +73,4 @@ share/fresh-rootca.pem
|
|||
tester/liblinphone_tester
|
||||
tools/lp-gen-wrappers
|
||||
tools/lpc2xml_test
|
||||
tools/xml2lpc_test
|
||||
tools/xml2lpc_test
|
||||
|
|
|
|||
18
CMakeLists.txt
Normal file
18
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
project(LINPHONE C)
|
||||
|
||||
option(LINPHONE_ENABLE_VIDEO "Build linphone with video support." ON)
|
||||
|
||||
include_directories(
|
||||
include/
|
||||
coreapi/
|
||||
${CMAKE_CURRENT_BINARY_DIR}/coreapi/
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
${CMAKE_INSTALL_PREFIX}/include/libxml2
|
||||
)
|
||||
|
||||
add_subdirectory(coreapi)
|
||||
add_subdirectory(share)
|
||||
|
|
@ -201,15 +201,12 @@ Portfile-devel: $(top_srcdir)/scripts/Portfile-devel.tmpl dist
|
|||
|
||||
MACAPPNAME=Linphone.app
|
||||
MACAPPZIP=$(PACKAGE)-$(VERSION).app.zip
|
||||
MACAPPDMG=$(PACKAGE)-$(VERSION).dmg
|
||||
BUNDLEPREFIX=./
|
||||
BUNDLEDIR=$(BUNDLEPREFIX)$(MACAPPNAME)
|
||||
LIBICONV_HACK=$(top_builddir)/build/macos/libiconv.2.dylib
|
||||
|
||||
$(LIBICONV_HACK):
|
||||
cd $(top_builddir)/build/macos && \
|
||||
wget http://download-mirror.savannah.gnu.org/releases/linphone/misc/libiconv.2.dylib
|
||||
|
||||
bundle: $(LIBICONV_HACK)
|
||||
bundle:
|
||||
rm -rf $(INSTALLDIR)
|
||||
$(MKDIR_P) $(INSTALLDIR)
|
||||
make install DESTDIR=$(INSTALLDIR)
|
||||
|
|
@ -222,8 +219,8 @@ bundle: $(LIBICONV_HACK)
|
|||
> $(BUNDLEDIR)/Contents/Resources/etc/pango/pangorc
|
||||
cp -f $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig
|
||||
sed -e 's:@executable_path.*/::g' $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig > $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules
|
||||
cp -f $(LIBICONV_HACK) $(BUNDLEDIR)/Contents/Resources/lib/.
|
||||
cd $(BUNDLEDIR)/.. && rm -f $(MACAPPZIP) && zip -r $(MACAPPZIP) $(MACAPPNAME) && cd -
|
||||
cd $(BUNDLEDIR)/.. && rm -f $(MAXAPPDMG) && hdiutil create $(MACAPPDMG) -srcfolder $(MACAPPNAME) -ov && cd -
|
||||
|
||||
###
|
||||
### CLEAN
|
||||
|
|
|
|||
24
NEWS
24
NEWS
|
|
@ -1,6 +1,18 @@
|
|||
linphone-3.7...??
|
||||
Liblinphone level improvements thanks to belle-sip new SIP stack:
|
||||
* multiple SIP transports simualtaneously now allowed
|
||||
linphone-3.7.0 -- February 20th, 2014
|
||||
Application level improvements:
|
||||
* It is now possible to configure multiple proxy accounts with different transports (UDP, TCP, TLS)
|
||||
* can work with IPv6 and IPv4 simultaneously
|
||||
* User can choose video rendering method on Linux
|
||||
* Video HD formats support added, leveraging on multiple cores for encoding if available
|
||||
* Keyboard can be used for DTMF input
|
||||
* Faster and higly responsive UI thanks to fully asynchronous operation of the liblinphone.
|
||||
* Addon of opus codec
|
||||
* Possibility to specify a remote provisionning http URI for configuration
|
||||
* LDAP search integration for Linux and MacOSX
|
||||
* is-composing notification in chat area
|
||||
|
||||
Liblinphone level improvements thanks to new "belle-sip" SIP stack:
|
||||
* multiple SIP transports simultaneously now allowed
|
||||
* IP dual stack: can use IPv6 and IPv4 simultaneously
|
||||
* fully asynchronous behavior: no more lengthly DNS or connections
|
||||
* +sip.instance parameter (RFC5626)
|
||||
|
|
@ -10,7 +22,13 @@ linphone-3.7...??
|
|||
* SIP transaction state machines improved (RFC6026)
|
||||
* Privacy API (RFC3323, RFC3325)
|
||||
* Full support of rich presence in (RFC4480)
|
||||
* Better handling of sips scheme in URIs.
|
||||
* Messaging: support of is-composing (RFC3994)
|
||||
* Call transfer fixes in error cases
|
||||
* Add API for managing SIP SUBSCRIBES/NOTIFY/PUBLISH (linphonecore/event.h)
|
||||
* bugfixes
|
||||
|
||||
Requires: mediastreamer2 = 2.10.0, ortp = 0.23.0, belle-sip = 1.3.0
|
||||
|
||||
linphone-3.6.1 -- June 17, 2013
|
||||
* fix memory leak with some video cameras on windows.
|
||||
|
|
|
|||
15
README
15
README
|
|
@ -8,7 +8,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol.
|
|||
- intltool
|
||||
|
||||
- you need at least:
|
||||
- belle-sip>=1.0.0
|
||||
- belle-sip>=1.3.0
|
||||
- speex>=1.2.0 (including libspeexdsp part)
|
||||
- libxml2
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol.
|
|||
- libavcodec (ffmpeg)
|
||||
- libswscale (part of ffmpeg too) for better scaling performance
|
||||
- libxv (x11 video extension)
|
||||
- ligl1-mesa (OpenGL API -- GLX development files)
|
||||
- libgl1-mesa (OpenGL API -- GLX development files)
|
||||
- libglew (OpenGL Extension Wrangler library)
|
||||
- libv4l (Video for linux)
|
||||
- libx11 (x11)
|
||||
|
|
@ -33,7 +33,7 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol.
|
|||
|
||||
Here is the command line to get these dependencies installed for Ubuntu && Debian
|
||||
|
||||
$ sudo apt-get install libtool intltool libgtk2.0-dev libosip2-dev libexosip2-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libxv-dev libgl1-mesa-dev libglew1.6-dev libv4l-dev libxml2-dev
|
||||
$ sudo apt-get install libtool intltool libgtk2.0-dev libspeexdsp-dev libavcodec-dev libswscale-dev libx11-dev libxv-dev libgl1-mesa-dev libglew1.6-dev libv4l-dev libxml2-dev
|
||||
|
||||
+ for optional library
|
||||
$ sudo apt-get install libreadline-dev libgsm1-dev libtheora-dev libsoup2.4-dev libsqlite3-dev libupnp4-dev
|
||||
|
|
@ -44,11 +44,12 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol.
|
|||
$ sudo make install
|
||||
|
||||
+ Install zrtpcpp (optional), for unbreakable call encryption
|
||||
$ sudo apt-get install cmake libssl-dev
|
||||
$ git clone git://git.linphone.org/zrtpcpp.git
|
||||
$ cd zrtpcpp && cmake -Denable-ccrtp=false . && make
|
||||
$ sudo apt-get install cmake
|
||||
$ git clone https://github.com/wernerd/ZRTPCPP.git
|
||||
$ cd ZRTPCPP
|
||||
$ cmake -DCORE_LIB=true -DSDES=false . && make
|
||||
$ sudo make install
|
||||
|
||||
If you get this error: "cc1plus: error: unrecognized command line option ‘-std=c++11’", edit CMakeLists.txt and replace c++11 by c++0x .
|
||||
|
||||
- Compile linphone
|
||||
|
||||
|
|
|
|||
63
README.macos
63
README.macos
|
|
@ -14,32 +14,34 @@ You need:
|
|||
+universal
|
||||
|
||||
- Install build time dependencies
|
||||
$ sudo port install automake autoconf libtool intltool
|
||||
$ sudo port install automake autoconf libtool intltool wget cunit
|
||||
|
||||
- Install some linphone dependencies with macports
|
||||
$ sudo port install speex
|
||||
$ sudo port install antlr3 speex libvpx readline sqlite3 libsoup openldap
|
||||
$ sudo port install ffmpeg-devel -gpl2
|
||||
$ sudo port install libvpx
|
||||
$ sudo port install readline
|
||||
|
||||
|
||||
- Install gtk. It is recommended to use the quartz backend for better integration.
|
||||
$ sudo port install gtk2 +quartz +no_x11
|
||||
$ sudo port install gtk-osx-application -python27
|
||||
$ sudo port install hicolor-icon-theme
|
||||
|
||||
- Install additional librairies required for wizard (linphone.org account creation assistant)
|
||||
$ sudo port install libsoup
|
||||
|
||||
- Install sqlite3 for message storage
|
||||
$ sudo port install sqlite3
|
||||
|
||||
The softwares below need to be compiled manually. To ensure compatibility with multiple mac os version it is recommended to do:
|
||||
The next pieces need to be compiled manually. To ensure compatibility with multiple mac os version it is recommended to do:
|
||||
$ export MACOSX_DEPLOYMENT_TARGET=10.6
|
||||
$ export CFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5"
|
||||
$ export OBJCFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5"
|
||||
$ export CXXFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5"
|
||||
$ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5"
|
||||
$ export LDFLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5 -Wl,-headerpad_max_install_names -Wl,-read_only_relocs -Wl,suppress"
|
||||
|
||||
- (Optional) libvpx-1.2 has a bug on macos resulting in ugly video. It is recommended to upgrade it manually to 1.3 from source.
|
||||
The libvpx build isn't able to produce dual architecture files. To workaround this, configure libvpx twice and use lipo to create a dual architecture
|
||||
libvpx.a .
|
||||
|
||||
- Install libantlr3c (library used by belle-sip for parsing)
|
||||
$ git clone -b linphone git://git.linphone.org/antlr3.git
|
||||
$ cd antlr3/runtime/C
|
||||
$ ./autogen.sh
|
||||
$ ./configure --disable-static --prefix=/opt/local && make
|
||||
$ sudo make install
|
||||
|
||||
- Install polarssl (encryption library used by belle-sip)
|
||||
$ git clone git://git.linphone.org/polarssl.git -b linphone
|
||||
|
|
@ -54,30 +56,27 @@ The softwares below need to be compiled manually. To ensure compatibility with m
|
|||
$ sudo make install
|
||||
|
||||
- Install srtp (optional) for call encryption
|
||||
$ sudo port install srtp
|
||||
If that fails, get from source:
|
||||
$ git clone git://git.linphone.org/srtp.git
|
||||
$ cd srtp && autoconf && ./configure --prefix=/opt/local && make libsrtp.a
|
||||
$ sudo make install
|
||||
|
||||
- Install zrtpcpp (optional), for unbreakable call encryption
|
||||
$ sudo port install cmake
|
||||
$ git clone git://git.linphone.org/zrtpcpp.git
|
||||
$ cd zrtpcpp && cmake -Denable-ccrtp=false . && make
|
||||
$ sudo make install
|
||||
$ git clone https://github.com/wernerd/ZRTPCPP.git
|
||||
$ cd ZRTPCPP
|
||||
$ cmake -DCORE_LIB=true -DSDES=false CMAKE_INSTALL_NAME_DIR=/usr/local/lib/ -DCMAKE_C_FLAGS="-arch i386 -arch x86_64 -mmacosx-version-min=10.5" -DCMAKE_CXX_FLAGS="-arch i386 -arch x86_64 --stdlib=libstdc++ -std=c++11 -lstdc++ -mmacosx-version-min=10.5" -DCMAKE_C_COMPILER=`xcrun --find clang` -DCMAKE_CXX_COMPILER=`xcrun --find clang` .
|
||||
$ sudo make install
|
||||
|
||||
** WARNING 2013-03-06 glib-networking is currently broken in macports - generates crashes or hangs when used in a bundle **
|
||||
As a temporary workaround, build a newer version by yourself:
|
||||
$ wget http://ftp.gnome.org/pub/gnome/sources/glib-networking/2.34/glib-networking-2.34.2.tar.xz
|
||||
$ tar -xvzf glib-networking-2.34.2.tar.xz
|
||||
$ cd glib-networking-2.34.2
|
||||
$ ./configure --prefix=/opt/local --without-ca-certificates && make
|
||||
$ sudo make install
|
||||
|
||||
- Install gsm codec (optional)
|
||||
$ git clone git://git.linphone.org/gsm.git
|
||||
$ cd gsm
|
||||
$ make CCFLAGS="$CFLAGS -c -O2 -DNeedFunctionPrototypes=1"
|
||||
$ sudo make install INSTALL_ROOT=/opt/local GSM_INSTALL_INC=/opt/local/include
|
||||
|
||||
- Compile and install the tunnel library (optional, proprietary extension only)
|
||||
|
||||
If you got the source code from git, run ./autogen.sh first
|
||||
|
||||
If you got the source code from git, run ./autogen.sh first.
|
||||
Then or otherwise, do:
|
||||
|
||||
$ ./configure --prefix=/opt/local && make && sudo make install
|
||||
|
|
@ -88,7 +87,7 @@ The softwares below need to be compiled manually. To ensure compatibility with m
|
|||
|
||||
Then or otherwise, do:
|
||||
|
||||
$ ./configure --prefix=/opt/local --with-readline=/opt/local --disable-x11 --with-srtp=/opt/local --with-gsm=/opt/local --enable-zrtp --disable-strict && make
|
||||
$ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure --prefix=/opt/local --with-readline=/opt/local --disable-x11 --with-srtp=/opt/local --with-gsm=/opt/local --enable-zrtp --disable-strict && make
|
||||
|
||||
Install to /opt/local
|
||||
|
||||
|
|
@ -104,6 +103,12 @@ Use git:
|
|||
#make this dummy charset.alias file for the bundler to be happy:
|
||||
$ sudo touch touch /opt/local/lib/charset.alias
|
||||
|
||||
The bundler file in build/macos/linphone.bundle expects some plugins to be installed in /opt/local/lib/mediastreamer/plugins .
|
||||
If you don't need plugins, remove or comment out this line from the bundler file:
|
||||
<binary >
|
||||
${prefix:ms2plugins}/lib/mediastreamer/plugins/*.*.so
|
||||
</binary>
|
||||
|
||||
Then run, inside linphone source tree:
|
||||
Run configure as told before but with "--enable-relativeprefix" appended.
|
||||
$ make
|
||||
|
|
@ -116,7 +121,7 @@ For a better appearance, you can install the gtk-quartz-engine (a gtk theme) tha
|
|||
$ git clone https://github.com/jralls/gtk-quartz-engine.git
|
||||
$ cd gtk-quartz-engine
|
||||
$ autoreconf -i
|
||||
$ ./configure --prefix=/opt/local && make
|
||||
$ ./configure --prefix=/opt/local CFLAGS="$CFLAGS -Wno-error" && make
|
||||
$ sudo make install
|
||||
|
||||
Generate a new bundle to have it included.
|
||||
|
|
|
|||
132
README.mingw
132
README.mingw
|
|
@ -1,15 +1,18 @@
|
|||
Software to install
|
||||
*******************
|
||||
|
||||
Download lastest mingw-get-inst.exe from http://www.mingw.org
|
||||
Run mingw-get-inst.exe. Choose "download lastest catalogues".
|
||||
In the feature list, select:
|
||||
* C compiler
|
||||
* C++ compiler
|
||||
* Mingw developer toolkit
|
||||
Let the installer fetch and install everything.
|
||||
Download lastest mingw-get-setup.exe from http://www.mingw.org
|
||||
Run mingw-get-setup.exe.
|
||||
In the package list, select and install:
|
||||
* mingw32-developer-tool
|
||||
* mingw32-base
|
||||
* mingw32-gcc-g++
|
||||
* msys-base
|
||||
|
||||
In mingw shell, run
|
||||
For more information:
|
||||
http://www.mingw.org/wiki/Getting_Started
|
||||
|
||||
In mingw shell (also refered as msys), run
|
||||
|
||||
mingw-get install msys-zip
|
||||
mingw-get install msys-unzip
|
||||
|
|
@ -37,7 +40,7 @@ unzip <path to linphone-deps>
|
|||
|
||||
#Install GTK+ Outcrop theme, the one used by linphone for distribution.
|
||||
cd /share/themes
|
||||
wget http://art.gnome.org/download/themes/gtk2/1122/GTK2-Outcrop.tar.gz
|
||||
wget ftp://ftp.gnome.org/mirror/gnome.org/teams/art.gnome.org/themes/gtk2/GTK2-Outcrop.tar.gz
|
||||
tar -xvzf GTK2-Outcrop.tar.gz
|
||||
|
||||
#To get the translations working, remove from C:/MinGW/lib :
|
||||
|
|
@ -45,70 +48,63 @@ libintl.a libintl.la libintl.dll.a
|
|||
|
||||
* Download and install Inno Setup Compiler (required only if you run 'make setup.exe'). Add it to your windows Path environment variable.
|
||||
|
||||
Get Linphone source code
|
||||
************************
|
||||
* Install msys-git from (http://code.google.com/p/msysgit/). During installation you are asked to make a choice about how line endings are treated by git. Choose "Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY IMPORTANT. OTHERS BREAK AUTOMAKE.
|
||||
|
||||
Install msys-git from (http://code.google.com/p/msysgit/). During installation you are asked to make a choice about how line endings are treated by git.
|
||||
Choose "Checkout line endings as they are, commit as they are". THIS CHOICE IS VERY IMPORTANT. OTHERS BREAK AUTOMAKE.
|
||||
|
||||
It is recommended that you create a directory somewhere with a path without any spaces or ~ characters, for example
|
||||
c:\sources\
|
||||
Within msys-git bash, do
|
||||
General rules for compilation
|
||||
*****************************
|
||||
|
||||
- It is recommended that you create a directory somewhere with a path without any spaces or ~ characters, for example c:\sources\.
|
||||
This is the place where source code must be compiled.
|
||||
- git commands (to retrieve source code) must be performed within msys-git terminal.
|
||||
- all other commands (configure, autogen.sh, make) must be done within the mingw shell (msys).
|
||||
In both msys and msys-git windows, change into the directory you created for sources:
|
||||
cd /c/sources
|
||||
git clone git://git.linphone.org/linphone.git --recursive
|
||||
|
||||
Building belle-sip
|
||||
******************
|
||||
* download the sources with msys-git shell using the following command:
|
||||
$ git clone git://git.linphone.org/belle-sip.git
|
||||
* compile and install
|
||||
$ ./autogen.sh
|
||||
$ ./configure --prefix=/usr --enable-shared --disable-static
|
||||
$ make && make install
|
||||
|
||||
Building
|
||||
********
|
||||
Building Linphone
|
||||
*****************
|
||||
|
||||
WARNING: During the build, windows might slow down suddenly. Using ctl+alt+del to start the windows system monitor,
|
||||
you might see a process 'LVpSRV.exe' or something like this that eats 90% of cpu.
|
||||
Kill it. Don't know what it is, but once killed, windows runs normally.
|
||||
* download the sources using the following command:
|
||||
$ git clone git://git.linphone.org/linphone.git --recursive
|
||||
|
||||
#Build linphone itself:
|
||||
#run autogen.sh after a git checkout or update
|
||||
* compile
|
||||
#always run autogen.sh after a git checkout or update
|
||||
$ ./autogen.sh
|
||||
|
||||
./autogen.sh
|
||||
$ ./configure --prefix=/usr --enable-shared --disable-static
|
||||
#note: in order to use the tunnel (commercial extension), append --enable-tunnel to the configure line above.
|
||||
|
||||
./configure --prefix=/usr --enable-shared --disable-static
|
||||
#note: in order to use the tunnel, append --enable-tunnel to the configure line above.
|
||||
$ make
|
||||
$ make install
|
||||
|
||||
#compile:
|
||||
#Option: make a portable binary zip of linphone
|
||||
$ make zip
|
||||
|
||||
make
|
||||
#additionally you can make binary installer if you have Inno Setup 5 installed in its default path
|
||||
|
||||
#now install to /usr, required for compilation of plugins.
|
||||
$ make setup.exe
|
||||
#now you're done, you have a fresh linphone windows installer in the current directory.
|
||||
|
||||
make install
|
||||
Building plugins (optional)
|
||||
***************************
|
||||
|
||||
#make a binary zip of linphone
|
||||
|
||||
make zip
|
||||
|
||||
#additionally you can make binary installer if you have Inno Setup 5 installed in its default path
|
||||
|
||||
make setup.exe
|
||||
|
||||
#now you're done, you have a fresh linphone windows installer in the current directory.
|
||||
|
||||
|
||||
|
||||
#build plugins
|
||||
cd mediastreamer2/plugins/msx264
|
||||
./autogen.sh
|
||||
PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static
|
||||
#make a binary zip of this plugin
|
||||
make zip
|
||||
#or make an installer
|
||||
make setup.exe
|
||||
|
||||
#the buddylookup plugin enables lookup of buddies in a remote database using xml-rpc over http/https.
|
||||
cd coreapi/plugins/buddylookup
|
||||
./autogen.sh
|
||||
PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static
|
||||
make
|
||||
#make a binary zip of this plugin
|
||||
make zip
|
||||
This the example for msx264 (H264 plugin), the same applies for other linphone plugins.
|
||||
$ cd mediastreamer2/plugins/msx264
|
||||
$ ./autogen.sh
|
||||
$ PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static
|
||||
#make a binary zip of this plugin
|
||||
$ make zip
|
||||
#or make an installer
|
||||
$ make setup.exe
|
||||
|
||||
|
||||
******************************************************
|
||||
|
|
@ -122,8 +118,8 @@ linphone-deps packages.
|
|||
|
||||
List of software included in linphone-deps:
|
||||
antlr3c (compiled)
|
||||
bzrtp (compiled)
|
||||
polarssl (compiled
|
||||
belle-sip (compiled)
|
||||
libsrtp (compiled)
|
||||
libavcodec, libavutil, libavformat, libavdevice, libswscale (compiled, all these from ffmpeg)
|
||||
libtheora (from the web)
|
||||
|
|
@ -161,14 +157,6 @@ When running "make install DESTDIR=<somepath>", somepath must be absolute and sh
|
|||
$ make install DESTDIR=/usr
|
||||
$ make install DESTDIR=/home/<myuser>/polarssl-install
|
||||
|
||||
- building belle-sip
|
||||
* download the sources with:
|
||||
$ git clone git://git.linphone.org/belle-sip.git
|
||||
* compile and install, assuming you have already compiled polarssl and antlr3c and installed in /.
|
||||
$ ./autogen.sh
|
||||
$ ./configure --prefix=/usr --enable-shared --disable-static
|
||||
$ make && make install && make install DESTDIR=/home/<myuser>/belle-sip-install
|
||||
|
||||
- building libsrtp
|
||||
* download the sources with
|
||||
$ git clone git://git.linphone.org/srtp.git
|
||||
|
|
@ -179,6 +167,14 @@ When running "make install DESTDIR=<somepath>", somepath must be absolute and sh
|
|||
$ make install
|
||||
$ make install DESTDIR=/home/<myuser>/libsrtp-install
|
||||
|
||||
- building bzrtp
|
||||
* download the sources with msys-git shell using the following command:
|
||||
$ git clone git://git.linphone.org/bzrtp.git
|
||||
* compile and install
|
||||
$ ./autogen.sh
|
||||
$ ./configure --prefix=/usr --enable-shared --disable-static
|
||||
$ make && make install
|
||||
|
||||
- building sqlite3
|
||||
* download the sources on the following website:
|
||||
http://www.sqlite.org/download.html (choose the sqlite-autoconf-3XXX.tar.gz)
|
||||
|
|
|
|||
94
README.zrtp
94
README.zrtp
|
|
@ -1,94 +0,0 @@
|
|||
ZRTP guide
|
||||
|
||||
== Downloads ==
|
||||
- SRTP
|
||||
http://sourceforge.net/projects/srtp/
|
||||
or "apt-get source libsrtp0" on Debian
|
||||
|
||||
- ZRTP (libzrtpcpp-2.0)
|
||||
http://www.gnutelephony.org/index.php/GNU_ZRTP
|
||||
|
||||
|
||||
== Patch libzrtpcpp ==
|
||||
Index: src/ZIDFile.cpp
|
||||
===================================================================
|
||||
--- src/ZIDFile.cpp (révision 754)
|
||||
+++ src/ZIDFile.cpp (copie de travail)
|
||||
@@ -78,10 +78,11 @@
|
||||
|
||||
// create save file name, rename and re-open
|
||||
// if rename fails, just unlink old ZID file and create a brand new file
|
||||
- // just a little inconnvenience for the user, need to verify new SAS
|
||||
+ // just a little inconvenience for the user, need to verify new SAS
|
||||
std::string fn = std::string(name) + std::string(".save");
|
||||
if (rename(name, fn.c_str()) < 0) {
|
||||
- unlink(name);
|
||||
+ // unlink(name);
|
||||
createZIDFile(name);
|
||||
return;
|
||||
}
|
||||
Index: src/libzrtpcpp/ZrtpCallback.h
|
||||
===================================================================
|
||||
--- src/libzrtpcpp/ZrtpCallback.h (révision 754)
|
||||
+++ src/libzrtpcpp/ZrtpCallback.h (copie de travail)
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
-#include <commoncpp/config.h>
|
||||
+//#include <commoncpp/config.h>
|
||||
#include <libzrtpcpp/ZrtpCodes.h>
|
||||
|
||||
/**
|
||||
Index: src/libzrtpcpp/ZIDRecord.h
|
||||
===================================================================
|
||||
--- src/libzrtpcpp/ZIDRecord.h (révision 754)
|
||||
+++ src/libzrtpcpp/ZIDRecord.h (copie de travail)
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
-#include <commoncpp/config.h>
|
||||
+//#include <commoncpp/config.h>
|
||||
|
||||
#define IDENTIFIER_LEN 12
|
||||
#define RS_LENGTH 32
|
||||
Index: CMakeLists.txt
|
||||
===================================================================
|
||||
--- CMakeLists.txt (révision 754)
|
||||
+++ CMakeLists.txt (copie de travail)
|
||||
@@ -124,11 +124,15 @@
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
add_definitions(-Wno-long-long -Wno-char-subscripts)
|
||||
add_definitions(-Wall -ansi -pedantic)
|
||||
+ add_definitions(-DNEW_STDCPP)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
-add_subdirectory(demo)
|
||||
|
||||
+if (enable_ccrtp)
|
||||
+ add_subdirectory(demo)
|
||||
+endif()
|
||||
+
|
||||
if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/package/)
|
||||
MESSAGE(STATUS "package dir not found")
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/package/)
|
||||
|
||||
|
||||
|
||||
== Create simlinks or move folders ==
|
||||
submodules/external/srtp -> path_to_your_srtp_source
|
||||
submodules/external/libzrtpcpp -> path_to_your_patched_zrtpcpp_source
|
||||
|
||||
|
||||
|
||||
== Compilation for Android ==
|
||||
ndk-build BUILD_GPLV3_ZRTP=1 -j5
|
||||
|
||||
|
||||
== Compilation for Desktop version ==
|
||||
First ortp: ./autogen.sh && ./configure --enable-zrtp && make -j5 && sudo make install
|
||||
Then mediastreamer2: ./autogen.sh && ./configure && make -j5 && sudo make install
|
||||
Finally linphone: ./autogen.sh && ./configure --enable-external-ortp && make -j5 && sudo make install
|
||||
|
||||
25
autogen.sh
25
autogen.sh
|
|
@ -1,5 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
srcdir=`dirname $0`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
THEDIR=`pwd`
|
||||
cd $srcdir
|
||||
|
||||
#AM_VERSION="1.10"
|
||||
if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then
|
||||
# automake-1.10 (recommended) is not available on Fedora 8
|
||||
|
|
@ -42,12 +48,17 @@ autoheader
|
|||
$AUTOMAKE --force-missing --add-missing --copy
|
||||
autoconf
|
||||
|
||||
if [ -x oRTP/autogen.sh ]; then
|
||||
echo "Generating build scripts in oRTP..."
|
||||
( cd oRTP && ./autogen.sh )
|
||||
set +x
|
||||
if [ "$srcdir" = "." ]; then
|
||||
if [ -x oRTP/autogen.sh ]; then
|
||||
echo "Generating build scripts in oRTP..."
|
||||
( cd oRTP && ./autogen.sh )
|
||||
fi
|
||||
|
||||
if [ -x mediastreamer2/autogen.sh ]; then
|
||||
echo "Generating build scripts in mediastreamer2..."
|
||||
( cd mediastreamer2 && ./autogen.sh )
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -x mediastreamer2/autogen.sh ]; then
|
||||
echo "Generating build scripts in mediastreamer2..."
|
||||
( cd mediastreamer2 && ./autogen.sh )
|
||||
fi
|
||||
cd $THEDIR
|
||||
|
|
|
|||
|
|
@ -60,7 +60,11 @@ LOCAL_SRC_FILES := \
|
|||
linphone_tunnel_config.c \
|
||||
message_storage.c \
|
||||
info.c \
|
||||
event.c
|
||||
event.c \
|
||||
xml.c \
|
||||
xml2lpc.c \
|
||||
lpc2xml.c \
|
||||
remote_provisioning.c
|
||||
|
||||
ifndef LINPHONE_VERSION
|
||||
LINPHONE_VERSION = "Devel"
|
||||
|
|
@ -83,6 +87,9 @@ LOCAL_CFLAGS += -DVIDEO_ENABLED
|
|||
ifeq ($(BUILD_X264),1)
|
||||
LOCAL_CFLAGS += -DHAVE_X264
|
||||
endif
|
||||
ifeq ($(BUILD_OPENH264),1)
|
||||
LOCAL_CFLAGS += -DHAVE_OPENH264
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_CONTACT_HEADER),1)
|
||||
|
|
@ -171,6 +178,11 @@ LOCAL_STATIC_LIBRARIES += \
|
|||
libmsx264 \
|
||||
libx264
|
||||
endif
|
||||
ifeq ($(BUILD_OPENH264),1)
|
||||
LOCAL_STATIC_LIBRARIES += \
|
||||
libmsopenh264 \
|
||||
libwels
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_UPNP),1)
|
||||
|
|
@ -184,30 +196,23 @@ ifeq ($(BUILD_SRTP), 1)
|
|||
LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE)
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
ifneq ($(TARGET_ARCH_ABI),armeabi)
|
||||
LOCAL_CFLAGS += -DHAVE_ILBC=1
|
||||
LOCAL_STATIC_LIBRARIES += libmsilbc
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES)
|
||||
LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES)
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS)
|
||||
LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES)
|
||||
LOCAL_CFLAGS += $(LIBLINPHONE_EXTENDED_CFLAGS)
|
||||
|
||||
ifeq ($(BUILD_GPLV3_ZRTP),1)
|
||||
LOCAL_SHARED_LIBRARIES += libssl-linphone libcrypto-linphone
|
||||
LOCAL_SHARED_LIBRARIES += libzrtpcpp
|
||||
|
||||
ifeq ($(BUILD_ZRTP),1)
|
||||
LOCAL_STATIC_LIBRARIES += libbzrtp
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_SRTP),1)
|
||||
LOCAL_SHARED_LIBRARIES += libsrtp
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_REMOTE_PROVISIONING),1)
|
||||
LOCAL_SRC_FILES += ../tools/xml2lpc.c \
|
||||
../tools/xml2lpc_jni.cc \
|
||||
../tools/lpc2xml.c \
|
||||
../tools/lpc2xml_jni.cc
|
||||
|
||||
LOCAL_STATIC_LIBRARIES += libsrtp
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_SQLITE),1)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ common_SRC_FILES := \
|
|||
register_tester.c \
|
||||
setup_tester.c \
|
||||
upnp_tester.c \
|
||||
eventapi_tester.c
|
||||
eventapi_tester.c \
|
||||
stun_tester.c \
|
||||
flexisip_tester.c \
|
||||
tester.c \
|
||||
remote_provisioning_tester.c
|
||||
|
||||
common_C_INCLUDES += \
|
||||
$(LOCAL_PATH) \
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ export EXTRA_ARGS="--workdir $bundle_res"
|
|||
export GIO_EXTRA_MODULES="$bundle_lib/gio/modules"
|
||||
export PANGO_LIBDIR="$bundle_lib"
|
||||
export PANGO_SYSCONFDIR="$bundle_etc"
|
||||
export DYLD_LIBRARY_PATH=
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,9 @@
|
|||
<binary>
|
||||
${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/engines/*.so
|
||||
</binary>
|
||||
<binary>
|
||||
${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/immodules/*.so
|
||||
</binary>
|
||||
<!-- Copy GIO modules, required for https access for wizard-->
|
||||
<binary>
|
||||
${prefix}/lib/gio/modules/libgiognutls.so
|
||||
|
|
@ -101,6 +104,15 @@
|
|||
want to copy in to the bundle. The "dest" attribute is
|
||||
optional, as usual. Bundler will find all translations of that
|
||||
library/program under the indicated directory and copy them.-->
|
||||
<translations name="linphone">
|
||||
${prefix}/share/locale
|
||||
</translations>
|
||||
<translations name="gdk-pixbuf">
|
||||
${prefix}/share/locale
|
||||
</translations>
|
||||
<translations name="glib20">
|
||||
${prefix}/share/locale
|
||||
</translations>
|
||||
<translations name="gtk20">
|
||||
${prefix}/share/locale
|
||||
</translations>
|
||||
|
|
@ -120,6 +132,11 @@
|
|||
${prefix:linphone}/share/pixmaps/linphone
|
||||
</data>
|
||||
|
||||
<data>
|
||||
${prefix:linphone}/share/images
|
||||
</data>
|
||||
|
||||
|
||||
<!-- Copy in the themes data. You may want to trim this to save space
|
||||
in your bundle. -->
|
||||
<data>
|
||||
|
|
@ -154,6 +171,10 @@
|
|||
<data dest="${bundle}/Contents/Resources/share/sounds/linphone/ringback.wav">
|
||||
${prefix:linphone}/share/sounds/linphone/ringback.wav
|
||||
</data>
|
||||
|
||||
<data dest="${bundle}/Contents/Resources/share/sounds/linphone/incoming_chat.wav">
|
||||
${prefix:linphone}/share/sounds/linphone/incoming_chat.wav
|
||||
</data>
|
||||
|
||||
<!-- Icon themes to copy. The "icons" property can be either of
|
||||
"auto", "all", or "none". All or none should be
|
||||
|
|
|
|||
13
build/redhat/INSTALL
Normal file
13
build/redhat/INSTALL
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
INSTALL :
|
||||
|
||||
Download and install the repo rpmforge :
|
||||
http://repoforge.org/use/
|
||||
|
||||
$ sudo rpm -Uvh <path to rpmforge rpm>
|
||||
|
||||
Download the linphone-release rpm
|
||||
$ sudo rpm -Uvh <path to linphone rpm>
|
||||
|
||||
$ sudo yum install linphone
|
||||
|
||||
|
||||
63
build/redhat/README
Normal file
63
build/redhat/README
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
**********************************
|
||||
* Compiling linphone on RedHat *
|
||||
**********************************
|
||||
|
||||
Download and install the repo rpmforge :
|
||||
http://repoforge.org/use/
|
||||
|
||||
$ sudo rpm -Uhv <path to rpmforge rpm>
|
||||
$ yum -y update
|
||||
|
||||
- Install build time dependencies
|
||||
$ sudo yum install libtool intltool
|
||||
|
||||
- Install others dependencies
|
||||
$ sudo yum install gtk2-devel
|
||||
$ sudo yum install ffmpeg-devel
|
||||
$ sudo yum install openldap-devel
|
||||
|
||||
- Install antlr3
|
||||
$ git clone git://git.linphone.org/antlr3.git
|
||||
$ cd antlr3
|
||||
$ sudo cp antlr-3.4-complete.jar /usr/share/java/antlr3.jar
|
||||
|
||||
- Download and install packages
|
||||
$ sudo rpm -Uhv ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-1.3.2-1.el6.x86_64.rpm
|
||||
$ sudo rpm -Uvh ftp://ftp.icm.edu.pl/vol/rzm2/linux-fedora/linux/epel/6/x86_64/polarssl-devel-1.3.2-1.el6.x86_64.rpm
|
||||
$ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-3.2-14.fc15.x86_64.rpm
|
||||
$ sudo rpm -Uhv ftp://ftp.pbone.net/mirror/archive.fedoraproject.org/fedora/linux/releases/15/Everything/x86_64/os/Packages/antlr3-C-devel-3.2-14.fc15.x86_64.rpm
|
||||
|
||||
- Git repository
|
||||
|
||||
Belle-sip : git clone git://git.linphone.org/belle-sip.git
|
||||
oRTP : git clone git://git.linphone.org/ortp.git
|
||||
Mediastreamer : git clone git://git.linphone.org/mediastreamer2.git
|
||||
|
||||
- Compile Belle-sip / oRTP / mediastreamer
|
||||
$ ./autogen.sh
|
||||
$ ./configure
|
||||
$ make && make rpm
|
||||
$ sudo rpm -Uvh <path to rpm and rpm-devel>
|
||||
|
||||
- Compile Linphone
|
||||
$ ./autogen.sh
|
||||
$ ./configure
|
||||
$ make && make rpm
|
||||
|
||||
- Compile msx264
|
||||
$ ./autogen.sh && ./configure && make
|
||||
$ make rpm
|
||||
|
||||
-Create yum repo :
|
||||
$ cd rpmbuild/RPMS/*arch*/
|
||||
$ createrepo .
|
||||
|
||||
Create a file "linphone-release.repo" in /etc/yum.repos.d/ with :
|
||||
|
||||
[linphone-release]
|
||||
name = Linphone for redhat
|
||||
baseurl = file/// *path to the new repo*
|
||||
enabled = 1
|
||||
gpgcheck = 0
|
||||
|
||||
$ sudo yum install linphone
|
||||
|
|
@ -117,7 +117,7 @@
|
|||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>__STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>__STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
|
|
@ -147,7 +147,7 @@
|
|||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>__STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>__STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
|
|
@ -207,6 +207,7 @@
|
|||
<ClCompile Include="..\..\..\coreapi\siplogin.c" />
|
||||
<ClCompile Include="..\..\..\coreapi\sipsetup.c" />
|
||||
<ClCompile Include="..\..\..\coreapi\TunnelManager.cc" />
|
||||
<ClCompile Include="..\..\..\coreapi\xml.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\coreapi\bellesip_sal\sal_impl.h" />
|
||||
|
|
@ -234,6 +235,9 @@
|
|||
<ProjectReference Include="..\..\..\..\msilbc\build\windows\msilbc\msilbc\msilbc.vcxproj">
|
||||
<Project>{072fad20-7007-4da2-b2e7-16ce2b219f67}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\msisac\build\windows\msisac\msisac\msisac.vcxproj">
|
||||
<Project>{b16b81a9-bef2-44c9-b603-1065183ae844}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\mssilk\build\windows\mssilk\mssilk\mssilk.vcxproj">
|
||||
<Project>{36b528f9-fb79-4078-a16b-0a7442581bb7}</Project>
|
||||
</ProjectReference>
|
||||
|
|
|
|||
166
configure.ac
166
configure.ac
|
|
@ -1,6 +1,6 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT([linphone],[3.6.99-linphone-daemon],[linphone-developers@nongnu.org])
|
||||
AC_INIT([linphone],[3.7.0-linphone-daemon],[linphone-developers@nongnu.org])
|
||||
AC_CANONICAL_SYSTEM
|
||||
AC_CONFIG_SRCDIR([coreapi/linphonecore.c])
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ if test "$LINPHONE_EXTRA_VERSION" != "" ;then
|
|||
LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION}
|
||||
fi
|
||||
|
||||
LIBLINPHONE_SO_CURRENT=5 dnl increment this number when you add/change/remove an interface
|
||||
LIBLINPHONE_SO_CURRENT=6 dnl increment this number when you add/change/remove an interface
|
||||
LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT
|
||||
LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface
|
||||
|
||||
|
|
@ -49,6 +49,8 @@ AM_PROG_CC_C_O
|
|||
AC_CHECK_PROGS(MD5SUM,[md5sum md5])
|
||||
AM_CONDITIONAL(HAVE_MD5SUM,test -n $MD5SUM)
|
||||
|
||||
ios_found=no
|
||||
|
||||
case $target in
|
||||
*mingw32ce)
|
||||
CFLAGS="$CFLAGS -D_WIN32_WCE -DORTP_STATIC -D_WIN32_WINNT=0x0501"
|
||||
|
|
@ -68,6 +70,7 @@ case $target in
|
|||
;;
|
||||
armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin)
|
||||
CFLAGS="$CFLAGS -DTARGET_OS_IPHONE=1 "
|
||||
LIBS="$LIBS -framework CoreFoundation -framework AudioToolbox -framework CoreAudio -framework Foundation -framework QuartzCore -framework OpenGLES -framework UIKit -framework AVFoundation"
|
||||
ios_found=yes
|
||||
;;
|
||||
x86_64-apple-darwin*|i686-apple-darwin*)
|
||||
|
|
@ -79,8 +82,7 @@ case $target in
|
|||
|
||||
esac
|
||||
|
||||
|
||||
|
||||
AM_CONDITIONAL(BUILD_IOS, test x$ios_found = xyes)
|
||||
|
||||
AC_SUBST(ACLOCAL_MACOS_FLAGS)
|
||||
AC_SUBST(CONSOLE_FLAGS)
|
||||
|
|
@ -165,6 +167,53 @@ AC_ARG_ENABLE(x11,
|
|||
[enable_x11=true]
|
||||
)
|
||||
|
||||
dnl conditional build of LDAP support
|
||||
AC_ARG_ENABLE(ldap,
|
||||
[AS_HELP_STRING([--enable-ldap], [Enables LDAP support (default=no)])],
|
||||
[case "${enableval}" in
|
||||
yes) enable_ldap=true ;;
|
||||
no) enable_ldap=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-ldap) ;;
|
||||
esac],
|
||||
[enable_ldap=false]
|
||||
)
|
||||
|
||||
if test "$enable_ldap" = "true"; then
|
||||
PKG_CHECK_MODULES(LDAP, [openldap],[found_ldap=yes], [found_ldap=no])
|
||||
if test "$found_ldap" = "no"; then
|
||||
AC_CHECK_LIB(ldap,ldap_initialize, [LDAP_LIBS="-lldap -llber"],
|
||||
[AC_MSG_ERROR([You need libldap for LDAP support])]
|
||||
)
|
||||
AC_CHECK_HEADERS(ldap.h, [foo=bar], [AC_MSG_ERROR( [ldap.h not found] ) ] )
|
||||
found_ldap=yes
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES(SASL, [libsasl2],[found_sasl=yes],[found_sasl=no] )
|
||||
|
||||
if test "$found_sasl" = "no"; then
|
||||
AC_CHECK_LIB(sasl2, sasl_client_init , [SASL_LIBS="-lsasl2"],
|
||||
[AC_MSG_ERROR([You need SASL for LDAP support] ) ]
|
||||
)
|
||||
AC_CHECK_HEADERS(sasl/sasl.h,foo=bar, [AC_MSG_ERROR([sasl/sasl.h not found])])
|
||||
found_sasl=yes
|
||||
fi
|
||||
|
||||
AC_SUBST(LDAP_CFLAGS)
|
||||
AC_SUBST(LDAP_LIBS)
|
||||
|
||||
AC_SUBST(SASL_CFLAGS)
|
||||
AC_SUBST(SASL_LIBS)
|
||||
|
||||
if test "$found_ldap$found_sasl" = "yesyes"; then
|
||||
AC_DEFINE(BUILD_LDAP,1,[Defined if LDAP build option enabled])
|
||||
else
|
||||
AC_MSG_ERROR([Can't use LDAP due to previous errors])
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_LDAP, test x$enable_ldap != xfalse)
|
||||
|
||||
dnl conditionnal build of console interface.
|
||||
AC_ARG_ENABLE(console_ui,
|
||||
[AS_HELP_STRING([--enable-console_ui=[yes/no]], [Turn on or off compilation of console interface (default=yes)])],
|
||||
|
|
@ -286,6 +335,15 @@ if test "$gtk_ui" = "true" ; then
|
|||
fi
|
||||
fi
|
||||
|
||||
case "$target" in
|
||||
#macosx 64 bits
|
||||
x86_64-apple-darwin*)
|
||||
LIBS="$LIBS -mmacosx-version-min=10.6"
|
||||
CXXFLAGS="$CXXFLAGS -mmacosx-version-min=10.6"
|
||||
CFLAGS="$CFLAGS -mmacosx-version-min=10.6"
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl os-specific problems not handled by existing macros.
|
||||
case "$host_os" in
|
||||
*freebsd*)
|
||||
|
|
@ -369,9 +427,9 @@ AC_ARG_ENABLE(debug,
|
|||
)
|
||||
AS_CASE([$debug_enabled],
|
||||
[yes],[
|
||||
CFLAGS="$CFLAGS -g -DDEBUG"
|
||||
CXXFLAGS="$CXXFLAGS -g -DDEBUG"
|
||||
OBJCFLAGS="$OBJCFLAGS -g -DDEBUG"
|
||||
CFLAGS="$CFLAGS -g -O0 -DDEBUG"
|
||||
CXXFLAGS="$CXXFLAGS -g -O0 -DDEBUG"
|
||||
OBJCFLAGS="$OBJCFLAGS -g -O0 -DDEBUG"
|
||||
],
|
||||
[no],
|
||||
[
|
||||
|
|
@ -435,7 +493,14 @@ if test "$relativeprefix" = "yes" ; then
|
|||
fi
|
||||
|
||||
dnl Set PACKAGE_LOCALE_DIR in config.h.
|
||||
DATADIRNAME=share
|
||||
case "$target_os" in
|
||||
*qnx*)
|
||||
DATADIRNAME=app/native/assets
|
||||
;;
|
||||
*)
|
||||
DATADIRNAME=share
|
||||
;;
|
||||
esac
|
||||
AC_DEFINE_UNQUOTED(PACKAGE_LOCALE_DIR, "${package_prefix}/${DATADIRNAME}/locale",[Defines the place where locales can be found])
|
||||
|
||||
AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${package_prefix}/${DATADIRNAME}",[Defines the place where data are found])
|
||||
|
|
@ -521,17 +586,6 @@ AC_ARG_ENABLE(zrtp,
|
|||
[zrtp=false]
|
||||
)
|
||||
|
||||
|
||||
AC_ARG_ENABLE(portaudio,
|
||||
[AS_HELP_STRING([--enable-portaudio], [Turn on portaudio native support compiling])],
|
||||
[case "${enableval}" in
|
||||
yes) portaudio=true ;;
|
||||
no) portaudio=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-portaudio) ;;
|
||||
esac],
|
||||
[portaudio=false]
|
||||
)
|
||||
|
||||
dnl build console if required
|
||||
AM_CONDITIONAL(BUILD_CONSOLE, test x$console_ui = xtrue)
|
||||
|
||||
|
|
@ -626,6 +680,39 @@ AC_SUBST(STRICT_OPTIONS)
|
|||
|
||||
top_srcdir=`dirname $0`
|
||||
|
||||
AC_ARG_ENABLE(external-ortp,
|
||||
[AS_HELP_STRING([--enable-external-ortp], [Use external oRTP library])],
|
||||
[case "${enableval}" in
|
||||
yes) external_ortp=true ;;
|
||||
no) external_ortp=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-external-ortp) ;;
|
||||
esac],
|
||||
[external_ortp=false]
|
||||
)
|
||||
|
||||
if test "$external_ortp" = 'true'; then
|
||||
PKG_CHECK_MODULES([ORTP], [ortp >= 0.23.0])
|
||||
ORTP_VERSION=`$PKG_CONFIG --modversion ortp`
|
||||
else
|
||||
AC_CONFIG_SUBDIRS( oRTP )
|
||||
ORTP_CFLAGS="-I\$(top_srcdir)/oRTP/include"
|
||||
ORTP_LIBS="\$(top_builddir)/oRTP/src/libortp.la"
|
||||
if test x$ac_cv_c_bigendian = xyes ; then
|
||||
ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN"
|
||||
fi
|
||||
if test x$ntptimestamp = xtrue ; then
|
||||
ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_TIMESTAMP"
|
||||
fi
|
||||
ORTP_DIR=oRTP
|
||||
changequote(<<, >>)
|
||||
ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'`
|
||||
changequote([, ])
|
||||
fi
|
||||
AC_SUBST(ORTP_CFLAGS)
|
||||
AC_SUBST(ORTP_LIBS)
|
||||
AC_SUBST([ORTP_VERSION])
|
||||
AC_SUBST([ORTP_DIR])
|
||||
|
||||
AC_ARG_ENABLE([external-mediastreamer],
|
||||
[AS_HELP_STRING([--enable-external-mediastreamer],[Use external mediastreamer library])],,
|
||||
[enable_external_mediastreamer=no]
|
||||
|
|
@ -633,7 +720,7 @@ AC_ARG_ENABLE([external-mediastreamer],
|
|||
|
||||
AS_CASE($enable_external_mediastreamer,
|
||||
[yes],
|
||||
[PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer])
|
||||
[PKG_CHECK_MODULES([MEDIASTREAMER], [mediastreamer >= 2.10.0])
|
||||
MS2_VERSION=`$PKG_CONFIG --modversion mediastreamer`],
|
||||
[no],
|
||||
[AC_CONFIG_SUBDIRS( mediastreamer2 )
|
||||
|
|
@ -683,7 +770,7 @@ AC_ARG_ENABLE(msg-storage,
|
|||
|
||||
AM_CONDITIONAL(BUILD_MSG_STORAGE, test x$enable_msg_storage = xtrue)
|
||||
if test x$enable_msg_storage != xfalse; then
|
||||
PKG_CHECK_MODULES(SQLITE3,[ sqlite3 >= 3.7.0],[
|
||||
PKG_CHECK_MODULES(SQLITE3,[ sqlite3 >= 3.6.0],[
|
||||
SQLITE3_CFLAGS+="-DMSG_STORAGE_ENABLED"
|
||||
AC_SUBST(SQLITE3_CFLAGS)
|
||||
AC_SUBST(SQLITE3_LIBS)
|
||||
|
|
@ -698,7 +785,7 @@ if test x$enable_msg_storage != xfalse; then
|
|||
fi
|
||||
|
||||
|
||||
PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.2.0])
|
||||
PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.3.1])
|
||||
|
||||
SIPSTACK_CFLAGS="$BELLESIP_CFLAGS"
|
||||
SIPSTACK_LIBS="$BELLESIP_LIBS"
|
||||
|
|
@ -713,7 +800,7 @@ AM_CONDITIONAL(ENABLE_MANUAL, test x$have_sgmltools$build_manual = xyesyes )
|
|||
|
||||
dnl for external use of linphone libs
|
||||
LINPHONE_CFLAGS="-I${includedir} -I${includedir}/linphone"
|
||||
LINPHONE_LIBS="-L${libdir} -llinphone -llpc2xml -lxml2lpc"
|
||||
LINPHONE_LIBS="-L${libdir} -llinphone"
|
||||
|
||||
AC_SUBST(LINPHONE_CFLAGS)
|
||||
AC_SUBST(LINPHONE_LIBS)
|
||||
|
|
@ -724,38 +811,7 @@ AC_DEFINE_UNQUOTED(LINPHONE_PLUGINS_DIR, "${package_prefix}/lib/liblinphone/plug
|
|||
LINPHONE_PLUGINS_DIR="${package_prefix}/lib/liblinphone/plugins"
|
||||
AC_SUBST(LINPHONE_PLUGINS_DIR)
|
||||
|
||||
AC_ARG_ENABLE(external-ortp,
|
||||
[AS_HELP_STRING([--enable-external-ortp], [Use external oRTP library])],
|
||||
[case "${enableval}" in
|
||||
yes) external_ortp=true ;;
|
||||
no) external_ortp=false ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-external-ortp) ;;
|
||||
esac],
|
||||
[external_ortp=false]
|
||||
)
|
||||
|
||||
if test "$external_ortp" = 'true'; then
|
||||
PKG_CHECK_MODULES([ORTP], [ortp])
|
||||
ORTP_VERSION=`$PKG_CONFIG --modversion ortp`
|
||||
else
|
||||
AC_CONFIG_SUBDIRS( oRTP )
|
||||
ORTP_CFLAGS="-I\$(top_srcdir)/oRTP/include"
|
||||
ORTP_LIBS="\$(top_builddir)/oRTP/src/libortp.la"
|
||||
if test x$ac_cv_c_bigendian = xyes ; then
|
||||
ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_BIGENDIAN"
|
||||
fi
|
||||
if test x$ntptimestamp = xtrue ; then
|
||||
ORTP_CFLAGS="$ORTP_CFLAGS -DORTP_TIMESTAMP"
|
||||
fi
|
||||
ORTP_DIR=oRTP
|
||||
changequote(<<, >>)
|
||||
ORTP_VERSION=`grep -E ^[AC]+_INIT ${top_srcdir}/oRTP/configure.ac | sed -e 's:^.*_INIT(.*,\[\(.*\)\]):\1:g'`
|
||||
changequote([, ])
|
||||
fi
|
||||
AC_SUBST(ORTP_CFLAGS)
|
||||
AC_SUBST(ORTP_LIBS)
|
||||
AC_SUBST([ORTP_VERSION])
|
||||
AC_SUBST([ORTP_DIR])
|
||||
|
||||
AC_ARG_ENABLE(tutorials,
|
||||
[AS_HELP_STRING([--disable-tutorials], [Disable compilation of tutorials])],
|
||||
|
|
@ -847,6 +903,7 @@ AC_CONFIG_FILES([
|
|||
share/xml/Makefile
|
||||
share/linphone.pc
|
||||
share/linphone.desktop
|
||||
share/audio-assistant.desktop
|
||||
scripts/Makefile
|
||||
tools/Makefile
|
||||
linphone.spec
|
||||
|
|
@ -865,6 +922,7 @@ printf "* %-30s %s\n" "Tools" $build_tools
|
|||
printf "* %-30s %s\n" "Message storage" $enable_msg_storage
|
||||
printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp
|
||||
printf "* %-30s %s\n" "uPnP support" $build_upnp
|
||||
printf "* %-30s %s\n" "LDAP support" $enable_ldap
|
||||
|
||||
if test "$enable_tunnel" = "true" ; then
|
||||
printf "* %-30s %s\n" "Tunnel support" "true"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ COMMON_CFLAGS=\
|
|||
$(MEDIASTREAMER_CFLAGS) \
|
||||
$(VIDEO_CFLAGS) \
|
||||
$(READLINE_CFLAGS) \
|
||||
$(SQLITE3_CFLAGS)
|
||||
$(SQLITE3_CFLAGS) \
|
||||
$(LIBXML2_CFLAGS)
|
||||
|
||||
if BUILD_CONSOLE
|
||||
|
||||
|
|
@ -24,11 +25,13 @@ bin_PROGRAMS+=linphoned
|
|||
endif
|
||||
|
||||
linphonec_SOURCES=linphonec.c linphonec.h commands.c
|
||||
linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS)
|
||||
linphonec_CFLAGS=$(COMMON_CFLAGS) $(CONSOLE_FLAGS) $(BELLESIP_CFLAGS)
|
||||
linphonec_LDADD=$(top_builddir)/coreapi/liblinphone.la \
|
||||
$(READLINE_LIBS) \
|
||||
$(SQLITE3_LIBS) \
|
||||
$(X11_LIBS)
|
||||
$(X11_LIBS) \
|
||||
$(BELLESIP_LIBS) \
|
||||
$(LIBXML2_LIBS)
|
||||
|
||||
if BUILD_WIN32
|
||||
#special build of linphonec to detach from the windows console
|
||||
|
|
|
|||
|
|
@ -558,10 +558,12 @@ lpc_cmd_call(LinphoneCore *lc, char *args)
|
|||
opt2=strstr(args,"--early-media");
|
||||
if (opt1){
|
||||
opt1[0]='\0';
|
||||
while(--opt1 > args && opt1[0]==' ') opt1[0]='\0';
|
||||
linphone_call_params_enable_video (cp,FALSE);
|
||||
}
|
||||
if (opt2){
|
||||
opt2[0]='\0';
|
||||
while(--opt2 > args && opt2[0]==' ') opt2[0]='\0';
|
||||
linphone_call_params_enable_early_media_sending(cp,TRUE);
|
||||
}
|
||||
if ( NULL == (call=linphone_core_invite_with_params(lc, args,cp)) )
|
||||
|
|
@ -615,8 +617,6 @@ lpc_cmd_chat(LinphoneCore *lc, char *args)
|
|||
}
|
||||
LinphoneChatRoom *cr = linphone_core_create_chat_room(lc,arg1);
|
||||
linphone_chat_room_send_message(cr,arg2);
|
||||
linphone_chat_room_destroy(cr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -1514,7 +1514,7 @@ linphonec_proxy_add(LinphoneCore *lc)
|
|||
continue;
|
||||
}
|
||||
|
||||
cfg=linphone_proxy_config_new();
|
||||
cfg=linphone_core_create_proxy_config(lc);
|
||||
if (linphone_proxy_config_set_server_addr(cfg,clean)<0)
|
||||
{
|
||||
linphonec_out("Invalid sip address (sip:sip.domain.tld).\n");
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ static char last_in_history[256];
|
|||
#endif
|
||||
//auto answer (-a) option
|
||||
static bool_t auto_answer=FALSE;
|
||||
static bool_t real_early_media_sending=FALSE;
|
||||
static bool_t answer_call=FALSE;
|
||||
static bool_t vcap_enabled=FALSE;
|
||||
static bool_t display_enabled=FALSE;
|
||||
|
|
@ -362,10 +363,17 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L
|
|||
linphone_call_enable_camera (call,linphonec_camera_enabled);
|
||||
id=(long)linphone_call_get_user_pointer (call);
|
||||
linphonec_set_caller(from);
|
||||
linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id);
|
||||
if ( auto_answer) {
|
||||
answer_call=TRUE;
|
||||
} else if (real_early_media_sending) {
|
||||
linphonec_out("Sending early media using real hardware\n");
|
||||
LinphoneCallParams* callparams = linphone_core_create_default_call_parameters(lc);
|
||||
linphone_call_params_enable_early_media_sending(callparams, TRUE);
|
||||
if (vcap_enabled) linphone_call_params_enable_video(callparams, TRUE);
|
||||
linphone_core_accept_early_media_with_params(lc, call, callparams);
|
||||
linphone_call_params_destroy(callparams);
|
||||
}
|
||||
linphonec_out("Receiving new incoming call from %s, assigned id %i\n", from,id);
|
||||
break;
|
||||
case LinphoneCallOutgoingInit:
|
||||
linphonec_call_identify(call);
|
||||
|
|
@ -906,6 +914,7 @@ print_usage (int exit_status)
|
|||
" -l logfile specify the log file for your SIP phone\n"
|
||||
" -s sipaddress specify the sip call to do at startup\n"
|
||||
" -a enable auto answering for incoming calls\n"
|
||||
" --real-early-media enable sending early media using real audio/video (beware of privacy issue)\n"
|
||||
" -V enable video features globally (disabled by default)\n"
|
||||
" -C enable video capture only (disabled by default)\n"
|
||||
" -D enable video display only (disabled by default)\n"
|
||||
|
|
@ -1229,6 +1238,10 @@ linphonec_parse_cmdline(int argc, char **argv)
|
|||
{
|
||||
auto_answer = TRUE;
|
||||
}
|
||||
else if (strncmp ("--real-early-media", argv[arg_num], strlen("--real-early-media")) == 0)
|
||||
{
|
||||
real_early_media_sending = TRUE;
|
||||
}
|
||||
else if (strncmp ("-C", argv[arg_num], 2) == 0)
|
||||
{
|
||||
vcap_enabled = TRUE;
|
||||
|
|
|
|||
148
coreapi/CMakeLists.txt
Normal file
148
coreapi/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
find_library(LIBORTP NAMES ortp)
|
||||
find_library(LIBMEDIASTREAMER_BASE NAMES mediastreamer_base)
|
||||
find_library(LIBMEDIASTREAMER_VOIP NAMES mediastreamer_voip)
|
||||
find_library(LIBBELLESIP NAMES bellesip)
|
||||
find_library(LIBXML2 NAMES xml2)
|
||||
|
||||
find_program(GIT git)
|
||||
|
||||
set(GIT_VERSION "unknown")
|
||||
if(GIT)
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMAND ${GIT} describe --always
|
||||
OUTPUT_VARIABLE GIT_DESCRIBE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMAND ${GIT} describe --abbrev=0
|
||||
OUTPUT_VARIABLE GIT_TAG
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
execute_process(
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMAND ${GIT} rev-parse HEAD
|
||||
OUTPUT_VARIABLE GIT_REVISION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(GIT_DESCRIBE)
|
||||
set(GIT_VERSION ${GIT_DESCRIBE})
|
||||
else(GIT_DESCRIBE)
|
||||
if(GIT_REVISION)
|
||||
set(GIT_VERSION ${GIT_REVISION})
|
||||
endif(GIT_REVISION)
|
||||
endif(GIT_DESCRIBE)
|
||||
endif(GIT)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "#define LIBLINPHONE_GIT_VERSION \"${GIT_VERSION}\""
|
||||
OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/liblinphone_gitversion.h
|
||||
)
|
||||
|
||||
set(SOURCE_FILES
|
||||
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
|
||||
callbacks.c
|
||||
chat.c
|
||||
conference.c
|
||||
ec-calibrator.c
|
||||
enum.c
|
||||
event.c
|
||||
friend.c
|
||||
info.c
|
||||
linphonecall.c
|
||||
linphonecore.c
|
||||
#linphone_tunnel.cc
|
||||
linphone_tunnel_stubs.c
|
||||
linphone_tunnel_config.c
|
||||
lpconfig.c
|
||||
lsd.c
|
||||
message_storage.c
|
||||
misc.c
|
||||
offeranswer.c
|
||||
presence.c
|
||||
proxy.c
|
||||
remote_provisioning.c
|
||||
sal.c
|
||||
siplogin.c
|
||||
sipsetup.c
|
||||
#TunnelManager.cc
|
||||
xml.c
|
||||
xml2lpc.c
|
||||
bellesip_sal/sal_impl.h
|
||||
enum.h
|
||||
event.h
|
||||
linphonecore.h
|
||||
linphonecore_utils.h
|
||||
linphonefriend.h
|
||||
linphone_tunnel.h
|
||||
lpconfig.h
|
||||
offeranswer.h
|
||||
private.h
|
||||
sipsetup.h
|
||||
xml2lpc.h
|
||||
)
|
||||
|
||||
add_definitions(
|
||||
-D_TRUE_TIME
|
||||
-DIN_LINPHONE
|
||||
-DUSE_BELLESIP
|
||||
#-DTUNNEL_ENABLED
|
||||
-DLINPHONE_PACKAGE_NAME="linphone"
|
||||
-DLINPHONE_VERSION="Devel"
|
||||
-DLIBLINPHONE_EXPORTS
|
||||
-DLINPHONE_PLUGINS_DIR=""
|
||||
)
|
||||
|
||||
if(LINPHONE_ENABLE_VIDEO)
|
||||
add_definitions(-DVIDEO_ENABLED)
|
||||
endif(LINPHONE_ENABLE_VIDEO)
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(
|
||||
-DWINDOW_NATIVE
|
||||
/FIliblinphone_gitversion.h
|
||||
)
|
||||
|
||||
set(LIBS ws2_32)
|
||||
endif(WIN32)
|
||||
set(LIBS ${LIBS} ${LIBORTP} ${LIBMEDIASTREAMER_BASE} ${LIBMEDIASTREAMER_VOIP} ${LIBBELLESIP} ${LIBXML2})
|
||||
|
||||
add_library(linphone SHARED ${SOURCE_FILES})
|
||||
set_target_properties(linphone PROPERTIES VERSION 3.7.0 SOVERSION 5)
|
||||
|
||||
target_link_libraries(linphone ${LIBS})
|
||||
|
||||
install(TARGETS linphone
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
|
||||
file(GLOB HEADER_FILES "*.h")
|
||||
|
||||
install(FILES ${HEADER_FILES}
|
||||
DESTINATION include/linphone
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
)
|
||||
if(WIN32)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/linphone.pdb
|
||||
DESTINATION bin
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
)
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
GITVERSION_FILE=liblinphone_gitversion.h
|
||||
GITVERSION_FILE_TMP=liblinphone_gitversion.h.tmp
|
||||
GITDESCRIBE=`cd $(top_srcdir) && git describe --always`
|
||||
|
|
@ -17,7 +18,7 @@ CLEANFILES=$(GITVERSION_FILE)
|
|||
## Process this file with automake to produce Makefile.in
|
||||
linphone_includedir=$(includedir)/linphone
|
||||
|
||||
linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonepresence.h linphonecore_utils.h lpconfig.h sipsetup.h event.h
|
||||
linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonepresence.h linphonecore_utils.h lpconfig.h sipsetup.h event.h xml2lpc.h lpc2xml.h
|
||||
|
||||
if BUILD_TUNNEL
|
||||
linphone_include_HEADERS+=linphone_tunnel.h
|
||||
|
|
@ -48,6 +49,13 @@ liblinphone_la_SOURCES=\
|
|||
message_storage.c \
|
||||
info.c \
|
||||
event.c event.h \
|
||||
contactprovider.c contactprovider.h contact_providers_priv.h \
|
||||
ldap/ldapprovider.c ldap/ldapprovider.h \
|
||||
dict.c \
|
||||
xml.c \
|
||||
xml2lpc.c \
|
||||
lpc2xml.c \
|
||||
remote_provisioning.c \
|
||||
$(GITVERSION_FILE)
|
||||
|
||||
if BUILD_UPNP
|
||||
|
|
@ -104,7 +112,8 @@ liblinphone_la_LIBADD= \
|
|||
$(TUNNEL_LIBS) \
|
||||
$(LIBSOUP_LIBS) \
|
||||
$(SQLITE3_LIBS) \
|
||||
$(LIBXML2_LIBS)
|
||||
$(LIBXML2_LIBS) \
|
||||
$(LDAP_LIBS) $(SASL_LIBS)
|
||||
|
||||
|
||||
if ENABLE_TESTS
|
||||
|
|
@ -139,7 +148,8 @@ AM_CFLAGS=\
|
|||
$(VIDEO_CFLAGS) \
|
||||
$(TUNNEL_CFLAGS) \
|
||||
$(SQLITE3_CFLAGS) \
|
||||
$(LIBXML2_CFLAGS)
|
||||
$(LIBXML2_CFLAGS) \
|
||||
$(LDAP_CFLAGS) $(SASL_CFLAGS)
|
||||
|
||||
if BUILD_WIZARD
|
||||
AM_CFLAGS+= -DBUILD_WIZARD
|
||||
|
|
|
|||
|
|
@ -53,11 +53,10 @@ 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);
|
||||
obj->works=FALSE;
|
||||
return obj;
|
||||
}
|
||||
|
||||
static LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){
|
||||
LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){
|
||||
LinphoneAuthInfo *obj=ms_new0(LinphoneAuthInfo,1);
|
||||
if (ai->username) obj->username=ms_strdup(ai->username);
|
||||
if (ai->userid) obj->userid=ms_strdup(ai->userid);
|
||||
|
|
@ -65,8 +64,6 @@ static LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){
|
|||
if (ai->ha1) obj->ha1=ms_strdup(ai->ha1);
|
||||
if (ai->realm) obj->realm=ms_strdup(ai->realm);
|
||||
if (ai->domain) obj->domain=ms_strdup(ai->domain);
|
||||
obj->works=FALSE;
|
||||
obj->usecount=0;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
@ -337,19 +334,26 @@ LinphoneAuthInfo * linphone_core_create_auth_info(LinphoneCore *lc, const char *
|
|||
*
|
||||
* This information will be used during all SIP transacations that require authentication.
|
||||
**/
|
||||
void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
|
||||
{
|
||||
void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info){
|
||||
LinphoneAuthInfo *ai;
|
||||
MSList *elem;
|
||||
MSList *l;
|
||||
int restarted_op_count=0;
|
||||
bool_t updating=FALSE;
|
||||
|
||||
if (info->ha1==NULL && info->passwd==NULL){
|
||||
ms_error("linphone_core_add_auth_info(): info supplied with empty password or ha1.");
|
||||
return;
|
||||
}
|
||||
/* find if we are attempting to modify an existing auth info */
|
||||
ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain);
|
||||
if (ai!=NULL && ai->domain && info->domain && strcmp(ai->domain, info->domain)==0){
|
||||
lc->auth_info=ms_list_remove(lc->auth_info,ai);
|
||||
linphone_auth_info_destroy(ai);
|
||||
updating=TRUE;
|
||||
}
|
||||
lc->auth_info=ms_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;
|
||||
|
|
@ -372,9 +376,20 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info)
|
|||
}
|
||||
}
|
||||
sal_op_authenticate(op,&sai);
|
||||
ai->usecount++;
|
||||
restarted_op_count++;
|
||||
}
|
||||
}
|
||||
if (l){
|
||||
ms_message("linphone_core_add_auth_info(): restarted [%i] operation(s) after %s auth info for\n"
|
||||
"\tusername: [%s]\n"
|
||||
"\trealm [%s]\n"
|
||||
"\tdomain [%s]\n",
|
||||
restarted_op_count,
|
||||
updating ? "updating" : "adding",
|
||||
info->username ? info->username : "",
|
||||
info->realm ? info->realm : "",
|
||||
info->domain ? info->domain : "");
|
||||
}
|
||||
ms_list_free(l);
|
||||
write_auth_infos(lc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,11 @@ SalAddress * sal_address_new(const char *uri){
|
|||
if (result) belle_sip_object_ref(result);
|
||||
return (SalAddress *)result;
|
||||
}
|
||||
|
||||
SalAddress * sal_address_clone(const SalAddress *addr){
|
||||
return (SalAddress *) belle_sip_object_ref(belle_sip_object_clone(BELLE_SIP_OBJECT(addr)));
|
||||
}
|
||||
|
||||
const char *sal_address_get_scheme(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);
|
||||
|
|
@ -123,7 +125,10 @@ void sal_address_set_port(SalAddress *addr, int port){
|
|||
void sal_address_clean(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) belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(uri));
|
||||
if (uri) {
|
||||
belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(uri));
|
||||
belle_sip_uri_headers_clean(uri);
|
||||
}
|
||||
belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(header_addr));
|
||||
return ;
|
||||
}
|
||||
|
|
@ -150,6 +155,17 @@ void sal_address_set_param(SalAddress *addr,const char* name,const char* value){
|
|||
return ;
|
||||
}
|
||||
|
||||
|
||||
void sal_address_set_params(SalAddress *addr, const char *params){
|
||||
belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(addr);
|
||||
belle_sip_parameters_set(parameters,params);
|
||||
}
|
||||
|
||||
void sal_address_set_uri_params(SalAddress *addr, const char *params){
|
||||
belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(addr)));
|
||||
belle_sip_parameters_set(parameters,params);
|
||||
}
|
||||
|
||||
void sal_address_set_transport(SalAddress* addr,SalTransport transport){
|
||||
if (!sal_address_is_secure(addr)){
|
||||
SAL_ADDRESS_SET(addr,transport_param,sal_transport_to_string(transport));
|
||||
|
|
@ -168,6 +184,17 @@ void sal_address_unref(SalAddress *addr){
|
|||
belle_sip_object_unref(BELLE_SIP_HEADER_ADDRESS(addr));
|
||||
}
|
||||
|
||||
bool_t sal_address_is_ipv6(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){
|
||||
const char *host=belle_sip_uri_get_host(uri);
|
||||
if (host && strchr(host,':')!=NULL)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void sal_address_destroy(SalAddress *addr){
|
||||
sal_address_unref(addr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,9 +115,14 @@ void sal_process_authentication(SalOp *op) {
|
|||
belle_sip_list_t* auth_list=NULL;
|
||||
belle_sip_auth_event_t* auth_event;
|
||||
belle_sip_response_t *response=belle_sip_transaction_get_response((belle_sip_transaction_t*)op->pending_auth_transaction);
|
||||
belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(initial_request,belle_sip_header_from_t);
|
||||
belle_sip_uri_t *from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from);
|
||||
|
||||
sal_add_pending_auth(op->base.root,op);
|
||||
|
||||
if (strcasecmp(belle_sip_uri_get_host(from_uri),"anonymous.invalid")==0){
|
||||
/*prefer using the from from the SalOp*/
|
||||
from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)sal_op_get_from_address(op));
|
||||
}
|
||||
|
||||
if (op->dialog && belle_sip_dialog_get_state(op->dialog)==BELLE_SIP_DIALOG_CONFIRMED) {
|
||||
new_request = belle_sip_dialog_create_request_from(op->dialog,initial_request);
|
||||
if (!new_request)
|
||||
|
|
@ -133,7 +138,7 @@ void sal_process_authentication(SalOp *op) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,&auth_list)) {
|
||||
if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,from_uri,&auth_list)) {
|
||||
if (is_within_dialog) {
|
||||
sal_op_send_request(op,new_request);
|
||||
} else {
|
||||
|
|
@ -141,23 +146,30 @@ void sal_process_authentication(SalOp *op) {
|
|||
}
|
||||
sal_remove_pending_auth(op->base.root,op);
|
||||
}else {
|
||||
ms_message("No auth info found for [%s]",sal_op_get_from(op));
|
||||
belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(response,belle_sip_header_from_t);
|
||||
char *tmp=belle_sip_object_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from)));
|
||||
ms_message("No auth info found for [%s]",tmp);
|
||||
belle_sip_free(tmp);
|
||||
sal_add_pending_auth(op->base.root,op);
|
||||
|
||||
if (is_within_dialog) {
|
||||
belle_sip_object_unref(new_request);
|
||||
}
|
||||
if (op->auth_info) sal_auth_info_delete(op->auth_info);
|
||||
}
|
||||
/*always store auth info, for case of wrong credential*/
|
||||
if (op->auth_info) sal_auth_info_delete(op->auth_info);
|
||||
if (auth_list){
|
||||
auth_event=(belle_sip_auth_event_t*)(auth_list->data);
|
||||
op->auth_info=sal_auth_info_create(auth_event);
|
||||
belle_sip_list_free_with_data(auth_list,(void (*)(void*))belle_sip_auth_event_destroy);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void process_dialog_terminated(void *sal, const belle_sip_dialog_terminated_event_t *event){
|
||||
belle_sip_dialog_t* dialog = belle_sip_dialog_terminated_event_get_dialog(event);
|
||||
SalOp* op = belle_sip_dialog_get_application_data(dialog);
|
||||
if (op && op->callbacks.process_dialog_terminated) {
|
||||
op->callbacks.process_dialog_terminated(op,event);
|
||||
if (op && op->callbacks && op->callbacks->process_dialog_terminated) {
|
||||
op->callbacks->process_dialog_terminated(op,event);
|
||||
} else {
|
||||
ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog);
|
||||
}
|
||||
|
|
@ -169,8 +181,10 @@ static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *e
|
|||
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(belle_sip_io_error_event_get_source(event));
|
||||
op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
|
||||
if (op->callbacks.process_io_error) {
|
||||
op->callbacks.process_io_error(op,event);
|
||||
/*also reset auth count on IO error*/
|
||||
op->auth_requests=0;
|
||||
if (op->callbacks && op->callbacks->process_io_error) {
|
||||
op->callbacks->process_io_error(op,event);
|
||||
}
|
||||
} else {
|
||||
/*ms_error("sal process_io_error not implemented yet for non transaction");*/
|
||||
|
|
@ -190,6 +204,7 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve
|
|||
belle_sip_response_t* resp;
|
||||
belle_sip_header_t *evh;
|
||||
const char *method=belle_sip_request_get_method(req);
|
||||
belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(req, belle_sip_header_contact_t);
|
||||
|
||||
from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t);
|
||||
|
||||
|
|
@ -237,7 +252,9 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve
|
|||
return;
|
||||
}else {
|
||||
ms_error("sal process_request_event not implemented yet for method [%s]",belle_sip_request_get_method(req));
|
||||
resp=belle_sip_response_create_from_request(req,501);
|
||||
resp=belle_sip_response_create_from_request(req,405);
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp)
|
||||
,BELLE_SIP_HEADER(belle_sip_header_allow_create("INVITE, CANCEL, ACK, BYE, SUBSCRIBE, NOTIFY, MESSAGE, OPTIONS, INFO")));
|
||||
belle_sip_provider_send_response(sal->prov,resp);
|
||||
return;
|
||||
}
|
||||
|
|
@ -249,6 +266,9 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve
|
|||
belle_sip_object_unref(address);
|
||||
}
|
||||
|
||||
if( remote_contact ){
|
||||
__sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact)));
|
||||
}
|
||||
|
||||
if (!op->base.to_address) {
|
||||
to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t);
|
||||
|
|
@ -276,8 +296,8 @@ static void process_request_event(void *ud, const belle_sip_request_event_t *eve
|
|||
sal_op_set_privacy_from_message(op,(belle_sip_message_t*)req);
|
||||
|
||||
sal_op_assign_recv_headers(op,(belle_sip_message_t*)req);
|
||||
if (op->callbacks.process_request_event) {
|
||||
op->callbacks.process_request_event(op,event);
|
||||
if (op->callbacks && op->callbacks->process_request_event) {
|
||||
op->callbacks->process_request_event(op,event);
|
||||
} else {
|
||||
ms_error("sal process_request_event not implemented yet");
|
||||
}
|
||||
|
|
@ -295,6 +315,7 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
|
|||
} else {
|
||||
SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
|
||||
belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
|
||||
belle_sip_header_contact_t* remote_contact = belle_sip_message_get_header_by_type(response, belle_sip_header_contact_t);
|
||||
|
||||
if (op->state == SalOpStateTerminated) {
|
||||
belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code);
|
||||
|
|
@ -303,13 +324,18 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
|
|||
if (!op->base.remote_ua) {
|
||||
sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response));
|
||||
}
|
||||
|
||||
if(remote_contact) {
|
||||
__sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact)));
|
||||
}
|
||||
|
||||
if (!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(response), belle_sip_header_call_id_t))));
|
||||
}
|
||||
|
||||
sal_op_assign_recv_headers(op,(belle_sip_message_t*)response);
|
||||
|
||||
if (op->callbacks.process_response_event) {
|
||||
if (op->callbacks && op->callbacks->process_response_event) {
|
||||
/*handle authorization*/
|
||||
switch (response_code) {
|
||||
case 200:
|
||||
|
|
@ -325,16 +351,27 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
|
|||
belle_sip_object_unref(op->pending_auth_transaction);
|
||||
op->pending_auth_transaction=NULL;
|
||||
}
|
||||
op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
|
||||
sal_process_authentication(op);
|
||||
return;
|
||||
if (++op->auth_requests > 2) {
|
||||
ms_warning("Auth info cannot be found for op [%s/%s] after 2 attempts, giving up",sal_op_get_from(op)
|
||||
,sal_op_get_to(op));
|
||||
op->base.root->callbacks.auth_failure(op,op->auth_info);
|
||||
sal_remove_pending_auth(op->base.root,op);
|
||||
} else {
|
||||
op->pending_auth_transaction=(belle_sip_client_transaction_t*)belle_sip_object_ref(client_transaction);
|
||||
sal_process_authentication(op);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 403:
|
||||
if (op->auth_info) op->base.root->callbacks.auth_failure(op,op->auth_info);
|
||||
break;
|
||||
}
|
||||
op->callbacks.process_response_event(op,event);
|
||||
if (response_code >= 180 && response_code !=401 && response_code !=407 && response_code !=403) {
|
||||
/*not an auth request*/
|
||||
op->auth_requests=0;
|
||||
}
|
||||
op->callbacks->process_response_event(op,event);
|
||||
} else {
|
||||
ms_error("Unhandled event response [%p]",event);
|
||||
}
|
||||
|
|
@ -344,8 +381,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even
|
|||
static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) {
|
||||
belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event);
|
||||
SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction));
|
||||
if (op && op->callbacks.process_timeout) {
|
||||
op->callbacks.process_timeout(op,event);
|
||||
if (op && op->callbacks && op->callbacks->process_timeout) {
|
||||
op->callbacks->process_timeout(op,event);
|
||||
} else {
|
||||
ms_error("Unhandled event timeout [%p]",event);
|
||||
}
|
||||
|
|
@ -362,8 +399,8 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans
|
|||
trans=BELLE_SIP_TRANSACTION(server_transaction);
|
||||
|
||||
op = (SalOp*)belle_sip_transaction_get_application_data(trans);
|
||||
if (op && op->callbacks.process_transaction_terminated) {
|
||||
op->callbacks.process_transaction_terminated(op,event);
|
||||
if (op && op->callbacks && op->callbacks->process_transaction_terminated) {
|
||||
op->callbacks->process_transaction_terminated(op,event);
|
||||
} else {
|
||||
ms_message("Unhandled transaction terminated [%p]",trans);
|
||||
}
|
||||
|
|
@ -412,6 +449,7 @@ Sal * sal_init(){
|
|||
sal->refresher_retry_after=60000; /*default value in ms*/
|
||||
return sal;
|
||||
}
|
||||
|
||||
void sal_set_user_pointer(Sal *sal, void *user_data){
|
||||
sal->up=user_data;
|
||||
}
|
||||
|
|
@ -464,6 +502,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
|
|||
ctx->callbacks.subscribe_presence_received=(SalOnSubscribePresenceReceived)unimplemented_stub;
|
||||
if (ctx->callbacks.text_received==NULL)
|
||||
ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub;
|
||||
if (ctx->callbacks.is_composing_received==NULL)
|
||||
ctx->callbacks.is_composing_received=(SalOnIsComposingReceived)unimplemented_stub;
|
||||
if (ctx->callbacks.ping_reply==NULL)
|
||||
ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub;
|
||||
if (ctx->callbacks.auth_requested==NULL)
|
||||
|
|
@ -503,14 +543,22 @@ int sal_transport_available(Sal *sal, SalTransport t){
|
|||
|
||||
int sal_add_listen_port(Sal *ctx, SalAddress* addr){
|
||||
int result;
|
||||
belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack
|
||||
,sal_address_get_domain(addr)
|
||||
,sal_address_get_port(addr)
|
||||
,sal_transport_to_string(sal_address_get_transport(addr)));
|
||||
belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(ctx->stack,
|
||||
sal_address_get_domain(addr),
|
||||
sal_address_get_port(addr),
|
||||
sal_transport_to_string(sal_address_get_transport(addr)));
|
||||
if (sal_address_get_port(addr)==-1 && lp==NULL){
|
||||
int random_port=(0xDFFF&random())+1024;
|
||||
ms_warning("This version of belle-sip doesn't support random port, choosing one here.");
|
||||
lp = belle_sip_stack_create_listening_point(ctx->stack,
|
||||
sal_address_get_domain(addr),
|
||||
random_port,
|
||||
sal_transport_to_string(sal_address_get_transport(addr)));
|
||||
}
|
||||
if (lp) {
|
||||
belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive);
|
||||
result = belle_sip_provider_add_listening_point(ctx->prov,lp);
|
||||
set_tls_properties(ctx);
|
||||
if (sal_address_get_transport(addr)==SalTransportTLS) set_tls_properties(ctx);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -527,22 +575,34 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i
|
|||
sal_address_destroy(sal_addr);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void remove_listening_point(belle_sip_listening_point_t* lp,belle_sip_provider_t* prov) {
|
||||
belle_sip_provider_remove_listening_point(prov,lp);
|
||||
}
|
||||
|
||||
int sal_get_listening_port(Sal *ctx, SalTransport tr){
|
||||
const char *tpn=sal_transport_to_string(tr);
|
||||
belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov, tpn);
|
||||
if (lp){
|
||||
return belle_sip_listening_point_get_port(lp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sal_unlisten_ports(Sal *ctx){
|
||||
const belle_sip_list_t * lps = belle_sip_provider_get_listening_points(ctx->prov);
|
||||
belle_sip_list_t * tmp_list = belle_sip_list_copy(lps);
|
||||
belle_sip_list_for_each2 (tmp_list,(void (*)(void*,void*))remove_listening_point,ctx->prov);
|
||||
belle_sip_list_free(tmp_list);
|
||||
|
||||
ms_message("sal_unlisten_ports done");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ortp_socket_t sal_get_socket(Sal *ctx){
|
||||
ms_warning("sal_get_socket is deprecated");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void sal_set_user_agent(Sal *ctx, const char *user_agent){
|
||||
belle_sip_header_user_agent_set_products(ctx->user_agent,NULL);
|
||||
belle_sip_header_user_agent_add_product(ctx->user_agent,user_agent);
|
||||
|
|
@ -704,6 +764,13 @@ void sal_set_dns_timeout(Sal* sal,int timeout) {
|
|||
int sal_get_dns_timeout(const Sal* sal) {
|
||||
return belle_sip_stack_get_dns_timeout(sal->stack);
|
||||
}
|
||||
|
||||
void sal_set_transport_timeout(Sal* sal,int timeout) {
|
||||
belle_sip_stack_set_transport_timeout(sal->stack, timeout);
|
||||
}
|
||||
int sal_get_transport_timeout(const Sal* sal) {
|
||||
return belle_sip_stack_get_transport_timeout(sal->stack);
|
||||
}
|
||||
void sal_enable_dns_srv(Sal *sal, bool_t enable) {
|
||||
belle_sip_stack_enable_dns_srv(sal->stack, (unsigned char)enable);
|
||||
}
|
||||
|
|
@ -762,16 +829,14 @@ int sal_auth_compute_ha1(const char* userid,const char* realm,const char* passwo
|
|||
SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){
|
||||
belle_sip_message_t *msg=(belle_sip_message_t*)ch;
|
||||
belle_sip_header_t *h;
|
||||
char *tmp=ms_strdup_printf("%s: %s\r\n",name,value);
|
||||
|
||||
if (msg==NULL){
|
||||
msg=(belle_sip_message_t*)belle_sip_request_new();
|
||||
belle_sip_object_ref(msg);
|
||||
}
|
||||
h=BELLE_SIP_HEADER(belle_sip_header_extension_parse(tmp));
|
||||
ms_free(tmp);
|
||||
h=belle_sip_header_create(name,value);
|
||||
if (h==NULL){
|
||||
belle_sip_error("Fail to parse extension header.");
|
||||
belle_sip_error("Fail to parse custom header.");
|
||||
return (SalCustomHeader*)msg;
|
||||
}
|
||||
belle_sip_message_add_header(msg,h);
|
||||
|
|
@ -783,11 +848,7 @@ const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){
|
|||
belle_sip_header_t *h=belle_sip_message_get_header((belle_sip_message_t*)ch,name);
|
||||
|
||||
if (h){
|
||||
if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_extension_t)){
|
||||
return belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(h));
|
||||
}else{
|
||||
return belle_sip_header_get_unparsed_value(h);
|
||||
}
|
||||
return belle_sip_header_get_unparsed_value(h);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
|
@ -810,11 +871,11 @@ const SalCustomHeader *sal_op_get_recv_custom_header(SalOp *op){
|
|||
|
||||
void sal_set_uuid(Sal *sal, const char *uuid){
|
||||
if (sal->uuid){
|
||||
belle_sip_free(sal->uuid);
|
||||
ms_free(sal->uuid);
|
||||
sal->uuid=NULL;
|
||||
}
|
||||
if (uuid)
|
||||
sal->uuid=belle_sip_strdup(uuid);
|
||||
sal->uuid=ms_strdup(uuid);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -915,5 +976,18 @@ unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){
|
|||
return belle_sip_random_bytes(ret,size);
|
||||
}
|
||||
|
||||
unsigned int sal_get_random(void){
|
||||
unsigned int ret=0;
|
||||
belle_sip_random_bytes((unsigned char*)&ret,4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
belle_sip_source_t * sal_create_timer(Sal *sal, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms, const char* timer_name) {
|
||||
belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack);
|
||||
return belle_sip_main_loop_create_timeout(ml, func, data, timeout_value_ms, timer_name);
|
||||
}
|
||||
|
||||
void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer) {
|
||||
belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack);
|
||||
belle_sip_main_loop_remove_source(ml, timer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,9 +76,11 @@ const char* sal_op_type_to_string(SalOpType type);
|
|||
|
||||
struct SalOp{
|
||||
SalOpBase base;
|
||||
belle_sip_listener_callbacks_t callbacks;
|
||||
const belle_sip_listener_callbacks_t *callbacks;
|
||||
SalErrorInfo 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;
|
||||
|
|
@ -98,6 +100,7 @@ struct SalOp{
|
|||
bool_t sdp_offering;
|
||||
bool_t call_released;
|
||||
bool_t manual_refresher;
|
||||
int auth_requests; /*number of auth requested for this op*/
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -130,13 +133,15 @@ 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,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size);
|
||||
void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) ;
|
||||
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_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*/
|
||||
|
|
@ -159,4 +164,6 @@ SalReason sal_reason_to_sip_code(SalReason r);
|
|||
|
||||
belle_sip_header_t * sal_make_supported_header(Sal *sal);
|
||||
|
||||
void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg);
|
||||
|
||||
#endif /* SAL_IMPL_H_ */
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "sal_impl.h"
|
||||
#include "offeranswer.h"
|
||||
|
||||
static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error);
|
||||
|
||||
/*used for calls terminated before creation of a dialog*/
|
||||
static void call_set_released(SalOp* op){
|
||||
if (!op->call_released){
|
||||
|
|
@ -36,19 +38,8 @@ static void call_set_released_and_unref(SalOp* op) {
|
|||
|
||||
|
||||
static void call_set_error(SalOp* op,belle_sip_response_t* response){
|
||||
SalError error=SalErrorUnknown;
|
||||
SalReason sr=SalReasonUnknown;
|
||||
belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
|
||||
char* reason=(char*)belle_sip_response_get_reason_phrase(response);
|
||||
int code = belle_sip_response_get_status_code(response);
|
||||
if (reason_header){
|
||||
reason = ms_strdup_printf("%s %s",reason,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header)));
|
||||
}
|
||||
sal_compute_sal_errors_from_code(code,&error,&sr);
|
||||
op->base.root->callbacks.call_failure(op,error,sr,reason,code);
|
||||
if (reason_header != NULL){
|
||||
ms_free(reason);
|
||||
}
|
||||
sal_op_set_error_info_from_response(op,response);
|
||||
op->base.root->callbacks.call_failure(op);
|
||||
}
|
||||
|
||||
static void sdp_process(SalOp *h){
|
||||
|
|
@ -84,8 +75,8 @@ static void sdp_process(SalOp *h){
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int set_sdp(belle_sip_message_t *msg,belle_sdp_session_description_t* session_desc) {
|
||||
belle_sip_header_content_type_t* content_type ;
|
||||
belle_sip_header_content_length_t* content_length;
|
||||
|
|
@ -125,7 +116,8 @@ static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event
|
|||
|
||||
if (!op->dialog) {
|
||||
/*call terminated very early*/
|
||||
op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503);
|
||||
sal_error_info_set(&op->error_info,SalReasonIOError,503,"IO error",NULL);
|
||||
op->base.root->callbacks.call_failure(op);
|
||||
call_set_released(op);
|
||||
} else {
|
||||
/*dialog will terminated shortly, nothing to do*/
|
||||
|
|
@ -159,10 +151,13 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat
|
|||
|
||||
static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) {
|
||||
belle_sdp_session_description_t* sdp;
|
||||
if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(response)))) {
|
||||
op->base.remote_media=sal_media_description_new();
|
||||
sdp_to_media_description(sdp,op->base.remote_media);
|
||||
if (op->base.local_media) sdp_process(op);
|
||||
SalReason reason;
|
||||
if (extract_sdp(BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) {
|
||||
if (sdp){
|
||||
op->base.remote_media=sal_media_description_new();
|
||||
sdp_to_media_description(sdp,op->base.remote_media);
|
||||
if (op->base.local_media) sdp_process(op);
|
||||
}/*if no sdp in response, what can we do ?*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +168,12 @@ static void cancelling_invite(SalOp* op ){
|
|||
sal_op_send_request(op,cancel);
|
||||
op->state=SalOpStateTerminating;
|
||||
}
|
||||
|
||||
static int vfu_retry (void *user_data, unsigned int events) {
|
||||
SalOp *op=(SalOp *)user_data;
|
||||
sal_call_send_vfu_request(op);
|
||||
sal_op_unref(op);
|
||||
return BELLE_SIP_STOP;
|
||||
}
|
||||
static void call_process_response(void *op_base, const belle_sip_response_event_t *event){
|
||||
SalOp* op = (SalOp*)op_base;
|
||||
belle_sip_request_t* ack;
|
||||
|
|
@ -182,6 +182,7 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
|
|||
belle_sip_request_t* req;
|
||||
belle_sip_response_t* response=belle_sip_response_event_get_response(event);
|
||||
int code = belle_sip_response_get_status_code(response);
|
||||
belle_sip_header_content_type_t *header_content_type=NULL;
|
||||
|
||||
|
||||
if (!client_transaction) {
|
||||
|
|
@ -221,6 +222,11 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
|
|||
call_set_error(op,response);
|
||||
if (op->dialog==NULL) call_set_released(op);
|
||||
}
|
||||
} else if ( code >=200
|
||||
&& code<300
|
||||
&& strcmp("UPDATE",belle_sip_request_get_method(req))==0) {
|
||||
handle_sdp_from_response(op,response);
|
||||
op->base.root->callbacks.call_accepted(op);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -247,7 +253,16 @@ static void call_process_response(void *op_base, const belle_sip_response_event_
|
|||
op->state=SalOpStateActive;
|
||||
} else if (code >= 300 && strcmp("INVITE",belle_sip_request_get_method(req))==0){
|
||||
call_set_error(op,response);
|
||||
} else {
|
||||
} else if (code == 491
|
||||
&& strcmp("INFO",belle_sip_request_get_method(req)) == 0
|
||||
&& (header_content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t))
|
||||
&& strcmp("application",belle_sip_header_content_type_get_type(header_content_type))==0
|
||||
&& strcmp("media_control+xml",belle_sip_header_content_type_get_subtype(header_content_type))==0) {
|
||||
unsigned int retry_in =1000*((float)rand()/RAND_MAX);
|
||||
belle_sip_source_t *s=sal_create_timer(op->base.root,vfu_retry,sal_op_ref(op), retry_in, "vfu request retry");
|
||||
ms_message("Rejected vfu request on op [%p], just retry in [%ui] ms",op,retry_in);
|
||||
belle_sip_object_unref(s);
|
||||
}else {
|
||||
/*ignoring*/
|
||||
}
|
||||
break;
|
||||
|
|
@ -280,7 +295,8 @@ static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t
|
|||
|
||||
if (!op->dialog) {
|
||||
/*call terminated very early*/
|
||||
op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408);
|
||||
sal_error_info_set(&op->error_info,SalReasonRequestTimeout,408,"Request timeout",NULL);
|
||||
op->base.root->callbacks.call_failure(op);
|
||||
call_set_released(op);
|
||||
} else {
|
||||
/*dialog will terminated shortly, nothing to do*/
|
||||
|
|
@ -317,22 +333,78 @@ static void call_terminated(SalOp* op,belle_sip_server_transaction_t* server_tra
|
|||
|
||||
static void unsupported_method(belle_sip_server_transaction_t* server_transaction,belle_sip_request_t* request) {
|
||||
belle_sip_response_t* resp;
|
||||
resp=belle_sip_response_create_from_request(request,500);
|
||||
resp=belle_sip_response_create_from_request(request,501);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
return;
|
||||
}
|
||||
|
||||
static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) {
|
||||
belle_sdp_session_description_t* sdp;
|
||||
if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(invite)))) {
|
||||
op->sdp_offering=FALSE;
|
||||
op->base.remote_media=sal_media_description_new();
|
||||
sdp_to_media_description(sdp,op->base.remote_media);
|
||||
belle_sip_object_unref(sdp);
|
||||
}else
|
||||
op->sdp_offering=TRUE;
|
||||
/*
|
||||
* Extract the sdp from a sip message.
|
||||
* If there is no body in the message, the session_desc is set to null, 0 is returned.
|
||||
* If body was present is not a SDP or parsing of SDP failed, -1 is returned and SalReason is set appropriately.
|
||||
*
|
||||
**/
|
||||
static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_description_t** session_desc, SalReason *error) {
|
||||
belle_sip_header_content_type_t* content_type=belle_sip_message_get_header_by_type(message,belle_sip_header_content_type_t);
|
||||
if (content_type){
|
||||
if (strcmp("application",belle_sip_header_content_type_get_type(content_type))==0
|
||||
&& strcmp("sdp",belle_sip_header_content_type_get_subtype(content_type))==0) {
|
||||
*session_desc=belle_sdp_session_description_parse(belle_sip_message_get_body(message));
|
||||
if (*session_desc==NULL) {
|
||||
ms_error("Failed to parse SDP message.");
|
||||
*error=SalReasonNotAcceptable;
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
*error=SalReasonUnsupportedContent;
|
||||
return -1;
|
||||
}
|
||||
}else *session_desc=NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_media_description_acceptable(SalMediaDescription *md){
|
||||
if (md->n_total_streams==0){
|
||||
ms_warning("Media description does not define any stream.");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) {
|
||||
belle_sdp_session_description_t* sdp;
|
||||
int err=0;
|
||||
SalReason reason;
|
||||
if (extract_sdp(BELLE_SIP_MESSAGE(invite),&sdp,&reason)==0) {
|
||||
if (sdp){
|
||||
op->sdp_offering=FALSE;
|
||||
op->base.remote_media=sal_media_description_new();
|
||||
sdp_to_media_description(sdp,op->base.remote_media);
|
||||
/*make some sanity check about the SDP received*/
|
||||
if (!is_media_description_acceptable(op->base.remote_media)){
|
||||
err=-1;
|
||||
reason=SalReasonNotAcceptable;
|
||||
}
|
||||
belle_sip_object_unref(sdp);
|
||||
}else op->sdp_offering=TRUE; /*INVITE without SDP*/
|
||||
}else err=-1;
|
||||
|
||||
if (err==-1){
|
||||
sal_call_decline(op,reason,NULL);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void sal_op_reset_descriptions(SalOp *op) {
|
||||
if (op->base.remote_media){
|
||||
sal_media_description_unref(op->base.remote_media);
|
||||
op->base.remote_media=NULL;
|
||||
}
|
||||
if (op->result){
|
||||
sal_media_description_unref(op->result);
|
||||
op->result=NULL;
|
||||
}
|
||||
}
|
||||
static void 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=NULL;
|
||||
|
|
@ -341,21 +413,29 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
belle_sip_dialog_state_t dialog_state;
|
||||
belle_sip_response_t* resp;
|
||||
belle_sip_header_t* call_info;
|
||||
const char *method=belle_sip_request_get_method(req);
|
||||
|
||||
if (strcmp("ACK",belle_sip_request_get_method(req))!=0){ /*ACK does'nt create srv transaction*/
|
||||
if (strcmp("ACK",method)!=0){ /*ACK does'nt create srv transaction*/
|
||||
server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event));
|
||||
belle_sip_object_ref(server_transaction);
|
||||
belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op);
|
||||
sal_op_ref(op);
|
||||
}
|
||||
|
||||
if (strcmp("INVITE",belle_sip_request_get_method(req))==0) {
|
||||
if (strcmp("INVITE",method)==0) {
|
||||
if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans);
|
||||
/*updating pending invite transaction*/
|
||||
op->pending_server_trans=server_transaction;
|
||||
belle_sip_object_ref(op->pending_server_trans);
|
||||
}
|
||||
|
||||
if (strcmp("UPDATE",method)==0) {
|
||||
if (op->pending_update_server_trans) belle_sip_object_unref(op->pending_update_server_trans);
|
||||
/*updating pending update transaction*/
|
||||
op->pending_update_server_trans=server_transaction;
|
||||
belle_sip_object_ref(op->pending_update_server_trans);
|
||||
}
|
||||
|
||||
if (!op->dialog) {
|
||||
set_or_update_dialog(op,belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(op->pending_server_trans)));
|
||||
ms_message("new incoming call from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op));
|
||||
|
|
@ -363,7 +443,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
dialog_state=belle_sip_dialog_get_state(op->dialog);
|
||||
switch(dialog_state) {
|
||||
case BELLE_SIP_DIALOG_NULL: {
|
||||
if (strcmp("INVITE",belle_sip_request_get_method(req))==0) {
|
||||
if (strcmp("INVITE",method)==0) {
|
||||
if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) {
|
||||
belle_sip_object_ref(op->replaces);
|
||||
} else if(op->replaces) {
|
||||
|
|
@ -373,20 +453,18 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
process_sdp_for_invite(op,req);
|
||||
|
||||
if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) {
|
||||
if( strstr(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(call_info)),"answer-after=") != NULL) {
|
||||
if( strstr(belle_sip_header_get_unparsed_value(call_info),"answer-after=") != NULL) {
|
||||
op->auto_answer_asked=TRUE;
|
||||
ms_message("The caller asked to automatically answer the call(Emergency?)\n");
|
||||
}
|
||||
}
|
||||
|
||||
op->base.root->callbacks.call_received(op);
|
||||
|
||||
break;
|
||||
} /* else same behavior as for EARLY state*/
|
||||
}
|
||||
case BELLE_SIP_DIALOG_EARLY: {
|
||||
//hmm probably a cancel
|
||||
if (strcmp("CANCEL",belle_sip_request_get_method(req))==0) {
|
||||
if (strcmp("CANCEL",method)==0) {
|
||||
if(belle_sip_request_event_get_server_transaction(event)) {
|
||||
/*first answer 200 ok to cancel*/
|
||||
belle_sip_server_transaction_send_response(server_transaction
|
||||
|
|
@ -402,9 +480,13 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
belle_sip_server_transaction_send_response(server_transaction
|
||||
,sal_op_create_response_from_request(op,req,481));
|
||||
}
|
||||
} else if (strcmp("PRACK",belle_sip_request_get_method(req))==0) {
|
||||
} else if (strcmp("PRACK",method)==0) {
|
||||
resp=sal_op_create_response_from_request(op,req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
} else if (strcmp("UPDATE",method)==0) {
|
||||
sal_op_reset_descriptions(op);
|
||||
if (process_sdp_for_invite(op,req)==0)
|
||||
op->base.root->callbacks.call_updating(op);
|
||||
} else {
|
||||
belle_sip_error("Unexpected method [%s] for dialog state BELLE_SIP_DIALOG_EARLY",belle_sip_request_get_method(req));
|
||||
unsupported_method(server_transaction,req);
|
||||
|
|
@ -413,42 +495,35 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
}
|
||||
case BELLE_SIP_DIALOG_CONFIRMED:
|
||||
/*great ACK received*/
|
||||
if (strcmp("ACK",belle_sip_request_get_method(req))==0) {
|
||||
if (strcmp("ACK",method)==0) {
|
||||
if (op->sdp_offering){
|
||||
if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(req)))){
|
||||
if (op->base.remote_media)
|
||||
sal_media_description_unref(op->base.remote_media);
|
||||
op->base.remote_media=sal_media_description_new();
|
||||
sdp_to_media_description(sdp,op->base.remote_media);
|
||||
sdp_process(op);
|
||||
belle_sip_object_unref(sdp);
|
||||
SalReason reason;
|
||||
if (extract_sdp(BELLE_SIP_MESSAGE(req),&sdp,&reason)==0){
|
||||
if (sdp){
|
||||
if (op->base.remote_media)
|
||||
sal_media_description_unref(op->base.remote_media);
|
||||
op->base.remote_media=sal_media_description_new();
|
||||
sdp_to_media_description(sdp,op->base.remote_media);
|
||||
sdp_process(op);
|
||||
belle_sip_object_unref(sdp);
|
||||
}else{
|
||||
ms_warning("SDP expected in ACK but not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
/*FIXME
|
||||
if (op->reinvite){
|
||||
op->reinvite=FALSE;
|
||||
}*/
|
||||
op->base.root->callbacks.call_ack(op);
|
||||
} else if(strcmp("BYE",belle_sip_request_get_method(req))==0) {
|
||||
} else if(strcmp("BYE",method)==0) {
|
||||
resp=sal_op_create_response_from_request(op,req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op));
|
||||
op->state=SalOpStateTerminating;
|
||||
/*call end not notified by dialog deletion because transaction can end before dialog*/
|
||||
} else if(strcmp("INVITE",belle_sip_request_get_method(req))==0) {
|
||||
} else if(strcmp("INVITE",method)==0) {
|
||||
/*re-invite*/
|
||||
if (op->base.remote_media){
|
||||
sal_media_description_unref(op->base.remote_media);
|
||||
op->base.remote_media=NULL;
|
||||
}
|
||||
if (op->result){
|
||||
sal_media_description_unref(op->result);
|
||||
op->result=NULL;
|
||||
}
|
||||
process_sdp_for_invite(op,req);
|
||||
|
||||
op->base.root->callbacks.call_updating(op);
|
||||
} else if (strcmp("INFO",belle_sip_request_get_method(req))==0){
|
||||
sal_op_reset_descriptions(op);
|
||||
if (process_sdp_for_invite(op,req)==0)
|
||||
op->base.root->callbacks.call_updating(op);
|
||||
} else if (strcmp("INFO",method)==0){
|
||||
if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))
|
||||
&& strstr(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),"picture_fast_update")) {
|
||||
/*vfu request*/
|
||||
|
|
@ -473,19 +548,19 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
}
|
||||
resp=sal_op_create_response_from_request(op,req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
}else if (strcmp("REFER",belle_sip_request_get_method(req))==0) {
|
||||
}else if (strcmp("REFER",method)==0) {
|
||||
sal_op_process_refer(op,event,server_transaction);
|
||||
} else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) {
|
||||
} else if (strcmp("NOTIFY",method)==0) {
|
||||
sal_op_call_process_notify(op,event,server_transaction);
|
||||
} else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==0) {
|
||||
} else if (strcmp("OPTIONS",method)==0) {
|
||||
resp=sal_op_create_response_from_request(op,req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
} else if (strcmp("CANCEL",belle_sip_request_get_method(req))==0) {
|
||||
} else if (strcmp("CANCEL",method)==0) {
|
||||
/*call leg does not exist because 200ok already sent*/
|
||||
belle_sip_server_transaction_send_response( server_transaction
|
||||
,sal_op_create_response_from_request(op,req,481));
|
||||
|
||||
} else{
|
||||
belle_sip_server_transaction_send_response(server_transaction,sal_op_create_response_from_request(op,req,481));
|
||||
} else if (strcmp("MESSAGE",method)==0){
|
||||
sal_process_incoming_message(op,event);
|
||||
}else{
|
||||
ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog);
|
||||
unsupported_method(server_transaction,req);
|
||||
}
|
||||
|
|
@ -522,7 +597,7 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){
|
|||
|
||||
static belle_sip_header_allow_t *create_allow(){
|
||||
belle_sip_header_allow_t* header_allow;
|
||||
header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
|
||||
header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO, UPDATE");
|
||||
return header_allow;
|
||||
}
|
||||
|
||||
|
|
@ -562,13 +637,18 @@ int sal_call(SalOp *op, const char *from, const char *to){
|
|||
return sal_op_send_request(op,invite);
|
||||
}
|
||||
|
||||
static belle_sip_listener_callbacks_t call_op_callbacks={0};
|
||||
|
||||
void sal_op_call_fill_cbs(SalOp*op) {
|
||||
op->callbacks.process_io_error=call_process_io_error;
|
||||
op->callbacks.process_response_event=call_process_response;
|
||||
op->callbacks.process_timeout=call_process_timeout;
|
||||
op->callbacks.process_transaction_terminated=call_process_transaction_terminated;
|
||||
op->callbacks.process_request_event=process_request_event;
|
||||
op->callbacks.process_dialog_terminated=process_dialog_terminated;
|
||||
if (call_op_callbacks.process_response_event==NULL){
|
||||
call_op_callbacks.process_io_error=call_process_io_error;
|
||||
call_op_callbacks.process_response_event=call_process_response;
|
||||
call_op_callbacks.process_timeout=call_process_timeout;
|
||||
call_op_callbacks.process_transaction_terminated=call_process_transaction_terminated;
|
||||
call_op_callbacks.process_request_event=process_request_event;
|
||||
call_op_callbacks.process_dialog_terminated=process_dialog_terminated;
|
||||
}
|
||||
op->callbacks=&call_op_callbacks;
|
||||
op->type=SalOpCall;
|
||||
}
|
||||
|
||||
|
|
@ -607,9 +687,8 @@ int sal_call_notify_ringing(SalOp *op, bool_t early_media){
|
|||
if (require) tags=belle_sip_header_get_unparsed_value(require);
|
||||
/* if client requires 100rel, then add necessary stuff*/
|
||||
if (tags && strstr(tags,"100rel")!=0) {
|
||||
|
||||
belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("Require","100rel")));
|
||||
belle_sip_message_add_header((belle_sip_message_t*)ringing_response,BELLE_SIP_HEADER(belle_sip_header_extension_create("RSeq","1")));
|
||||
belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("Require","100rel"));
|
||||
belle_sip_message_add_header((belle_sip_message_t*)ringing_response,belle_sip_header_create("RSeq","1"));
|
||||
}
|
||||
|
||||
#ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING
|
||||
|
|
@ -631,14 +710,21 @@ int sal_call_notify_ringing(SalOp *op, bool_t early_media){
|
|||
int sal_call_accept(SalOp*h){
|
||||
belle_sip_response_t *response;
|
||||
belle_sip_header_contact_t* contact_header;
|
||||
belle_sip_server_transaction_t* transaction;
|
||||
|
||||
if (!h->pending_server_trans) {
|
||||
/*first check if an UPDATE transaction need to be accepted*/
|
||||
if (h->pending_update_server_trans) {
|
||||
transaction=h->pending_update_server_trans;
|
||||
} else if (h->pending_server_trans) {
|
||||
/*so it must be an invite/re-invite*/
|
||||
transaction=h->pending_server_trans;
|
||||
} else {
|
||||
ms_error("No transaction to accept for op [%p]",h);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ms_message("Accepting server transaction [%p] on op [%p]", transaction, h);
|
||||
/* sends a 200 OK */
|
||||
response = sal_op_create_response_from_request(h,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(h->pending_server_trans)),200);
|
||||
response = sal_op_create_response_from_request(h,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(transaction)),200);
|
||||
|
||||
if (response==NULL){
|
||||
ms_error("Fail to build answer for call");
|
||||
|
|
@ -654,10 +740,16 @@ int sal_call_accept(SalOp*h){
|
|||
if ((contact_header=sal_op_create_contact(h))) {
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header));
|
||||
}
|
||||
|
||||
_sal_op_add_custom_headers(h, BELLE_SIP_MESSAGE(response));
|
||||
|
||||
handle_offer_answer_response(h,response);
|
||||
|
||||
belle_sip_server_transaction_send_response(h->pending_server_trans,response);
|
||||
belle_sip_server_transaction_send_response(transaction,response);
|
||||
if (h->pending_update_server_trans) {
|
||||
belle_sip_object_unref(h->pending_update_server_trans);
|
||||
h->pending_update_server_trans=NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -669,7 +761,7 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti
|
|||
if (reason==SalReasonRedirect){
|
||||
if (redirection!=NULL) {
|
||||
if (strstr(redirection,"sip:")!=0) status=302;
|
||||
status=380;
|
||||
else status=380;
|
||||
contact= belle_sip_header_contact_new();
|
||||
belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact),belle_sip_uri_parse(redirection));
|
||||
} else {
|
||||
|
|
@ -683,11 +775,22 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti
|
|||
}
|
||||
|
||||
int sal_call_update(SalOp *op, const char *subject){
|
||||
belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE");
|
||||
if (reinvite){
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject));
|
||||
sal_op_fill_invite(op, reinvite);
|
||||
return sal_op_send_request(op,reinvite);
|
||||
|
||||
belle_sip_request_t *update;
|
||||
belle_sip_dialog_state_t state=belle_sip_dialog_get_state(op->dialog);
|
||||
/*check for dialog state*/
|
||||
if ( state == BELLE_SIP_DIALOG_CONFIRMED) {
|
||||
update=belle_sip_dialog_create_request(op->dialog,"INVITE");
|
||||
} else if (state == BELLE_SIP_DIALOG_EARLY) {
|
||||
update=belle_sip_dialog_create_request(op->dialog,"UPDATE");
|
||||
} else {
|
||||
ms_error("Cannot update op [%p] with dialog [%p] in state [%s]",op, op->dialog,belle_sip_dialog_state_to_string(state));
|
||||
return -1;
|
||||
}
|
||||
if (update){
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(update),belle_sip_header_create( "Subject", subject));
|
||||
sal_op_fill_invite(op, update);
|
||||
return sal_op_send_request(op,update);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even
|
|||
|
||||
ms_message("Receiving NOTIFY request on op [%p]",op);
|
||||
if (header_event
|
||||
&& strncasecmp(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(header_event)),"refer",strlen("refer"))==0
|
||||
&& 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
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher
|
|||
,unsigned int status_code
|
||||
,const char* reason_phrase) {
|
||||
SalOp* op = (SalOp*)user_pointer;
|
||||
SalError error=SalErrorUnknown;
|
||||
SalReason sr=SalReasonUnknown;
|
||||
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;
|
||||
|
|
@ -50,8 +48,10 @@ static void subscribe_refresher_listener (belle_sip_refresher_t* refresher
|
|||
set_or_update_dialog(op,belle_sip_transaction_get_dialog(tr));
|
||||
}
|
||||
if (status_code>=200){
|
||||
sal_compute_sal_errors_from_code(status_code,&error,&sr);
|
||||
op->base.root->callbacks.subscribe_response(op,sss,error,sr);
|
||||
sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL);
|
||||
op->base.root->callbacks.subscribe_response(op,sss);
|
||||
}else if (status_code==0){
|
||||
op->base.root->callbacks.on_expire(op);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -170,13 +170,18 @@ static void subscribe_process_request_event(void *op_base, const belle_sip_reque
|
|||
}
|
||||
}
|
||||
|
||||
static belle_sip_listener_callbacks_t op_subscribe_callbacks={ 0 };
|
||||
|
||||
void sal_op_subscribe_fill_cbs(SalOp*op) {
|
||||
op->callbacks.process_io_error=subscribe_process_io_error;
|
||||
op->callbacks.process_response_event=subscribe_response_event;
|
||||
op->callbacks.process_timeout=subscribe_process_timeout;
|
||||
op->callbacks.process_transaction_terminated=subscribe_process_transaction_terminated;
|
||||
op->callbacks.process_request_event=subscribe_process_request_event;
|
||||
op->callbacks.process_dialog_terminated=subscribe_process_dialog_terminated;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,9 @@ void sal_op_release_impl(SalOp *op){
|
|||
|
||||
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 ;
|
||||
}
|
||||
|
|
@ -88,18 +90,23 @@ SalAuthInfo * sal_op_get_auth_requested(SalOp *op){
|
|||
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_secure(contact_uri,sal_op_is_secure(op));
|
||||
|
||||
if (op->privacy!=SalPrivacyNone){
|
||||
belle_sip_uri_set_user(contact_uri,NULL);
|
||||
}
|
||||
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){
|
||||
|
|
@ -205,16 +212,29 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) {
|
|||
sal_op_send_request(op,request);
|
||||
}
|
||||
|
||||
static void add_headers(belle_sip_header_t *h, belle_sip_message_t *msg){
|
||||
if (belle_sip_message_get_header(msg,belle_sip_header_get_name(h))==NULL)
|
||||
belle_sip_message_add_header(msg,h);
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
static void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){
|
||||
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_for_each2(l,(void (*)(void *, void *))add_headers,msg);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -227,6 +247,11 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req
|
|||
int result =-1;
|
||||
belle_sip_uri_t *next_hop_uri=NULL;
|
||||
|
||||
if (add_contact) {
|
||||
contact = sal_op_create_contact(op);
|
||||
belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact));
|
||||
}
|
||||
|
||||
_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) {
|
||||
|
|
@ -276,14 +301,10 @@ static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* req
|
|||
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 (add_contact) {
|
||||
contact = sal_op_create_contact(op);
|
||||
belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact));
|
||||
}
|
||||
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);
|
||||
belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL);
|
||||
}
|
||||
result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/);
|
||||
|
||||
|
|
@ -319,6 +340,12 @@ int sal_op_send_request(SalOp* op, belle_sip_request_t* request) {
|
|||
SalReason 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;
|
||||
|
|
@ -334,7 +361,7 @@ SalReason sal_reason_to_sip_code(SalReason r){
|
|||
case SalReasonForbidden:
|
||||
ret=403;
|
||||
break;
|
||||
case SalReasonMedia:
|
||||
case SalReasonUnsupportedContent:
|
||||
ret=415;
|
||||
break;
|
||||
case SalReasonNotFound:
|
||||
|
|
@ -356,102 +383,153 @@ SalReason sal_reason_to_sip_code(SalReason r){
|
|||
ret=401;
|
||||
break;
|
||||
case SalReasonNotAcceptable:
|
||||
ret=488;
|
||||
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;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) {
|
||||
SalReason _sal_reason_from_sip_code(int code) {
|
||||
if (code>=100 && code<300) return SalReasonNone;
|
||||
|
||||
switch(code) {
|
||||
case 400:
|
||||
*sal_err=SalErrorUnknown;
|
||||
break;
|
||||
case 0:
|
||||
return SalReasonIOError;
|
||||
case 301:
|
||||
return SalReasonMovedPermanently;
|
||||
case 302:
|
||||
return SalReasonRedirect;
|
||||
case 401:
|
||||
case 407:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonUnauthorized;
|
||||
break;
|
||||
return SalReasonUnauthorized;
|
||||
case 403:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonForbidden;
|
||||
break;
|
||||
return SalReasonForbidden;
|
||||
case 404:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonNotFound;
|
||||
break;
|
||||
return SalReasonNotFound;
|
||||
case 408:
|
||||
return SalReasonRequestTimeout;
|
||||
case 410:
|
||||
return SalReasonGone;
|
||||
case 415:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonMedia;
|
||||
break;
|
||||
return SalReasonUnsupportedContent;
|
||||
case 422:
|
||||
ms_error ("422 not implemented yet");;
|
||||
break;
|
||||
case 480:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonTemporarilyUnavailable;
|
||||
break;
|
||||
return SalReasonTemporarilyUnavailable;
|
||||
case 481:
|
||||
return SalReasonNoMatch;
|
||||
case 484:
|
||||
return SalReasonAddressIncomplete;
|
||||
case 486:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonBusy;
|
||||
break;
|
||||
return SalReasonBusy;
|
||||
case 487:
|
||||
break;
|
||||
return SalReasonNone;
|
||||
case 488:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonNotAcceptable;
|
||||
break;
|
||||
return SalReasonNotAcceptable;
|
||||
case 491:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonRequestPending;
|
||||
break;
|
||||
return SalReasonRequestPending;
|
||||
case 501:
|
||||
return SalReasonNotImplemented;
|
||||
case 502:
|
||||
return SalReasonBadGateway;
|
||||
case 504:
|
||||
return SalReasonServerTimeout;
|
||||
case 600:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonDoNotDisturb;
|
||||
break;
|
||||
return SalReasonDoNotDisturb;
|
||||
case 603:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonDeclined;
|
||||
break;
|
||||
return SalReasonDeclined;
|
||||
case 503:
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonServiceUnavailable;
|
||||
break;
|
||||
return SalReasonServiceUnavailable;
|
||||
default:
|
||||
if (code>=300){
|
||||
*sal_err=SalErrorFailure;
|
||||
*sal_reason=SalReasonUnknown;
|
||||
}else if (code>=100){
|
||||
*sal_err=SalErrorNone;
|
||||
*sal_reason=SalReasonUnknown;
|
||||
}else if (code==0){
|
||||
*sal_err=SalErrorNoResponse;
|
||||
}
|
||||
/* no break */
|
||||
return SalReasonUnknown;
|
||||
}
|
||||
return SalReasonUnknown;
|
||||
}
|
||||
|
||||
const SalErrorInfo *sal_error_info_none(void){
|
||||
static SalErrorInfo none={
|
||||
SalReasonNone,
|
||||
"Ok",
|
||||
200,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
return &none;
|
||||
}
|
||||
|
||||
void sal_error_info_reset(SalErrorInfo *ei){
|
||||
if (ei->status_string){
|
||||
ms_free(ei->status_string);
|
||||
ei->status_string=NULL;
|
||||
}
|
||||
if (ei->warnings){
|
||||
ms_free(ei->warnings);
|
||||
ei->warnings=NULL;
|
||||
|
||||
}
|
||||
if (ei->full_string){
|
||||
ms_free(ei->full_string);
|
||||
ei->full_string=NULL;
|
||||
}
|
||||
ei->protocol_code=0;
|
||||
ei->reason=SalReasonNone;
|
||||
}
|
||||
|
||||
void sal_error_info_set(SalErrorInfo *ei, SalReason reason, int code, const char *status_string, const char *warning){
|
||||
sal_error_info_reset(ei);
|
||||
if (reason==SalReasonUnknown) ei->reason=_sal_reason_from_sip_code(code);
|
||||
else ei->reason=reason;
|
||||
ei->protocol_code=code;
|
||||
ei->status_string=status_string ? ms_strdup(status_string) : NULL;
|
||||
ei->warnings=warning ? ms_strdup(warning) : NULL;
|
||||
if (ei->status_string){
|
||||
if (ei->warnings)
|
||||
ei->full_string=ms_strdup_printf("%s %s",ei->status_string,ei->warnings);
|
||||
else ei->full_string=ms_strdup(ei->status_string);
|
||||
}
|
||||
}
|
||||
/*return TRUE if error code*/
|
||||
bool_t sal_compute_sal_errors(belle_sip_response_t* response,SalError* sal_err,SalReason* sal_reason,char* reason, size_t reason_size) {
|
||||
int code = belle_sip_response_get_status_code(response);
|
||||
belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
|
||||
*sal_err=SalErrorUnknown;
|
||||
*sal_reason = SalReasonUnknown;
|
||||
|
||||
if (reason_header){
|
||||
snprintf(reason
|
||||
,reason_size
|
||||
,"%s %s"
|
||||
,belle_sip_response_get_reason_phrase(response)
|
||||
,belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(reason_header)));
|
||||
} else {
|
||||
strncpy(reason,belle_sip_response_get_reason_phrase(response),reason_size);
|
||||
}
|
||||
if (code>=400) {
|
||||
sal_compute_sal_errors_from_code(code,sal_err,sal_reason);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
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);
|
||||
/*Remark: the reason header is to be used mainly in SIP requests, thus the use and prototype of this function should be changed.*/
|
||||
belle_sip_header_t* reason_header = belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"Reason");
|
||||
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;
|
||||
if (warnings==NULL) warnings=reason_header ? belle_sip_header_get_unparsed_value(reason_header) : NULL;
|
||||
sal_error_info_set(ei,SalReasonUnknown,code,reason_phrase,warnings);
|
||||
}
|
||||
|
||||
const SalErrorInfo *sal_op_get_error_info(const SalOp *op){
|
||||
return &op->error_info;
|
||||
}
|
||||
|
||||
void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) {
|
||||
|
|
@ -540,7 +618,11 @@ void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){
|
|||
}
|
||||
|
||||
const char *sal_op_get_remote_contact(const SalOp *op){
|
||||
return sal_custom_header_find(op->base.recv_custom_headers,"Contact");
|
||||
/*
|
||||
* remote contact is filled in process_response
|
||||
* return sal_custom_header_find(op->base.recv_custom_headers,"Contact");
|
||||
*/
|
||||
return op->base.remote_contact;
|
||||
}
|
||||
|
||||
void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body){
|
||||
|
|
@ -606,3 +688,42 @@ bool_t sal_op_is_secure(const SalOp* op) {
|
|||
void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled){
|
||||
op->manual_refresher=enabled;
|
||||
}
|
||||
|
||||
bool_t sal_op_is_ipv6(SalOp *op){
|
||||
belle_sip_transaction_t *tr=NULL;
|
||||
belle_sip_header_address_t *contact;
|
||||
belle_sip_request_t *req;
|
||||
|
||||
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){
|
||||
ms_error("Unable to determine IP version from signaling operation.");
|
||||
return FALSE;
|
||||
}
|
||||
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){
|
||||
ms_error("Unable to determine IP version from signaling operation, no contact header found.");
|
||||
}
|
||||
return sal_address_is_ipv6((SalAddress*)contact);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
static void process_error( SalOp* op) {
|
||||
if (op->dir == SalOpDirOutgoing) {
|
||||
op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed);
|
||||
op->base.root->callbacks.text_delivery_update(op, SalTextDeliveryFailed);
|
||||
} else {
|
||||
ms_warning("unexpected io error for incoming message on op [%p]",op);
|
||||
}
|
||||
|
|
@ -30,44 +30,31 @@ static void process_error( SalOp* op) {
|
|||
|
||||
static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){
|
||||
SalOp* op = (SalOp*)user_ctx;
|
||||
// belle_sip_object_t* source = belle_sip_io_error_event_get_source(event);
|
||||
// if (BELLE_SIP_IS_INSTANCE_OF(source,belle_sip_transaction_t)) {
|
||||
// /*reset op to make sure transaction terminated does not need op*/
|
||||
// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(source),NULL);
|
||||
// }
|
||||
sal_error_info_set(&op->error_info,SalReasonIOError,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;
|
||||
// belle_sip_client_transaction_t *client_transaction=belle_sip_timeout_event_get_client_transaction(event);
|
||||
// belle_sip_server_transaction_t *server_transaction=belle_sip_timeout_event_get_server_transaction(event);
|
||||
// /*reset op to make sure transaction terminated does not need op*/
|
||||
// if (client_transaction) {
|
||||
// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);
|
||||
// } else {
|
||||
// belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),NULL);
|
||||
// }
|
||||
sal_error_info_set(&op->error_info,SalReasonRequestTimeout,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;
|
||||
/*belle_sip_client_transaction_t *client_transaction=belle_sip_response_event_get_client_transaction(event);*/
|
||||
int code = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
|
||||
SalTextDeliveryStatus status;
|
||||
sal_op_set_error_info_from_response(op,belle_sip_response_event_get_response(event));
|
||||
|
||||
if (code>=100 && code <200)
|
||||
status=SalTextDeliveryInProgress;
|
||||
else if (code>=200 && code <300)
|
||||
status=SalTextDeliveryDone;
|
||||
else
|
||||
status=SalTextDeliveryFailed;
|
||||
if (status != SalTextDeliveryInProgress) {
|
||||
/*reset op to make sure transaction terminated does not need op
|
||||
belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*/
|
||||
}
|
||||
|
||||
op->base.root->callbacks.text_delivery_update(op,status);
|
||||
|
||||
}
|
||||
|
||||
static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) {
|
||||
return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0
|
||||
&& strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0;
|
||||
|
|
@ -76,9 +63,16 @@ 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 bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) {
|
||||
return strcmp("application",belle_sip_header_content_type_get_type(content_type))==0
|
||||
&& strcmp("im-iscomposing+xml",belle_sip_header_content_type_get_subtype(content_type))==0;
|
||||
}
|
||||
|
||||
static void process_request_event(void *op_base, const belle_sip_request_event_t *event) {
|
||||
SalOp* op = (SalOp*)op_base;
|
||||
static void add_message_accept(belle_sip_message_t *msg){
|
||||
belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml"));
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -88,9 +82,6 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
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);
|
||||
SalMessage salmsg;
|
||||
char message_id[256]={0};
|
||||
int response_code=501;
|
||||
char* from;
|
||||
bool_t plain_text=FALSE;
|
||||
bool_t external_body=FALSE;
|
||||
|
|
@ -99,7 +90,13 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t);
|
||||
if (content_type && ((plain_text=is_plain_text(content_type))
|
||||
|| (external_body=is_external_body(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);
|
||||
|
||||
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));
|
||||
|
|
@ -120,15 +117,30 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t
|
|||
belle_sip_object_unref(address);
|
||||
belle_sip_free(from);
|
||||
if (salmsg.url) ms_free((char*)salmsg.url);
|
||||
response_code=200;
|
||||
} else if (content_type && is_im_iscomposing(content_type)) {
|
||||
SalIsComposing saliscomposing;
|
||||
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));
|
||||
saliscomposing.from=from;
|
||||
saliscomposing.text=belle_sip_message_get_body(BELLE_SIP_MESSAGE(req));
|
||||
op->base.root->callbacks.is_composing_received(op,&saliscomposing);
|
||||
resp = belle_sip_response_create_from_request(req,200);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
belle_sip_object_unref(address);
|
||||
belle_sip_free(from);
|
||||
} else {
|
||||
ms_error("Unsupported MESSAGE with content type [%s/%s]",belle_sip_header_content_type_get_type(content_type)
|
||||
,belle_sip_header_content_type_get_subtype(content_type));
|
||||
response_code=501; /*not implemented sound appropriate*/
|
||||
ms_error("Unsupported MESSAGE (content-type not recognized)");
|
||||
resp = belle_sip_response_create_from_request(req,415);
|
||||
add_message_accept((belle_sip_message_t*)resp);
|
||||
belle_sip_server_transaction_send_response(server_transaction,resp);
|
||||
return;
|
||||
}
|
||||
resp = belle_sip_response_create_from_request(req,response_code);
|
||||
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){
|
||||
|
|
@ -137,16 +149,21 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
|
|||
size_t content_length = msg?strlen(msg):0;
|
||||
time_t curtime=time(NULL);
|
||||
|
||||
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;
|
||||
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 (sal_op_get_contact(op)){
|
||||
belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
|
||||
req=sal_op_build_request(op,"MESSAGE");
|
||||
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)));
|
||||
|
|
@ -157,14 +174,30 @@ int sal_message_send(SalOp *op, const char *from, const char *to, const char* co
|
|||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static belle_sip_listener_callbacks_t op_message_callbacks={0};
|
||||
|
||||
void sal_op_message_fill_cbs(SalOp*op) {
|
||||
op->callbacks.process_io_error=process_io_error;
|
||||
op->callbacks.process_response_event=process_response_event;
|
||||
op->callbacks.process_timeout=process_timeout;
|
||||
op->callbacks.process_request_event=process_request_event;
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceMo
|
|||
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);
|
||||
ms_free(contact_info);
|
||||
belle_sip_free(contact_info);
|
||||
if (content == NULL) return;
|
||||
}
|
||||
|
||||
|
|
@ -44,8 +44,6 @@ void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceMo
|
|||
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){
|
||||
|
|
@ -96,13 +94,12 @@ static void presence_response_event(void *op_base, const belle_sip_response_even
|
|||
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);
|
||||
char reason[256]={0};
|
||||
SalError error=SalErrorUnknown;
|
||||
SalReason sr=SalReasonUnknown;
|
||||
belle_sip_header_expires_t* expires;
|
||||
|
||||
sal_op_set_error_info_from_response(op,response);
|
||||
|
||||
if (sal_compute_sal_errors(response,&error,&sr,reason, sizeof(reason))) {
|
||||
ms_error("subscription to [%s] rejected reason [%s]",sal_op_get_to(op),reason[0]!=0?reason:sal_reason_to_string(sr));
|
||||
if (code>=300) {
|
||||
ms_message("subscription to [%s] rejected",sal_op_get_to(op));
|
||||
op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/
|
||||
return;
|
||||
}
|
||||
|
|
@ -269,13 +266,18 @@ static void presence_process_request_event(void *op_base, const belle_sip_reques
|
|||
}
|
||||
}
|
||||
|
||||
static belle_sip_listener_callbacks_t op_presence_callbacks={0};
|
||||
|
||||
void sal_op_presence_fill_cbs(SalOp*op) {
|
||||
op->callbacks.process_io_error=presence_process_io_error;
|
||||
op->callbacks.process_response_event=presence_response_event;
|
||||
op->callbacks.process_timeout=presence_process_timeout;
|
||||
op->callbacks.process_transaction_terminated=presence_process_transaction_terminated;
|
||||
op->callbacks.process_request_event=presence_process_request_event;
|
||||
op->callbacks.process_dialog_terminated=presence_process_dialog_terminated;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,35 +24,39 @@ static void publish_refresher_listener (belle_sip_refresher_t* refresher
|
|||
,unsigned int status_code
|
||||
,const char* reason_phrase) {
|
||||
SalOp* op = (SalOp*)user_pointer;
|
||||
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));
|
||||
belle_sip_response_t *response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(last_publish_trans));
|
||||
/*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/
|
||||
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==412){
|
||||
/*resubmit the request after removing the SIP-If-Match*/
|
||||
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));
|
||||
belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match");
|
||||
belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES);
|
||||
}else if (status_code==0){
|
||||
op->base.root->callbacks.on_expire(op);
|
||||
}else if (status_code>=200){
|
||||
SalError err;
|
||||
SalReason reason;
|
||||
sal_compute_sal_errors_from_code(status_code,&err,&reason);
|
||||
op->base.root->callbacks.on_publish_response(op,err,reason);
|
||||
sal_error_info_set(&op->error_info,SalReasonUnknown,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;
|
||||
int code=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event));
|
||||
SalError err;
|
||||
SalReason reason;
|
||||
sal_compute_sal_errors_from_code(code,&err,&reason);
|
||||
op->base.root->callbacks.on_publish_response(op,err,reason);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void sal_op_publish_fill_cbs(SalOp*op) {
|
||||
op->callbacks.process_response_event=publish_response_event;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -72,7 +76,7 @@ int sal_publish_presence(SalOp *op, const char *from, const char *to, int expire
|
|||
|
||||
op->type=SalOpPublish;
|
||||
req=sal_op_build_request(op,"PUBLISH");
|
||||
if (sal_op_get_contact(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","presence"));
|
||||
|
|
@ -97,12 +101,14 @@ int sal_publish(SalOp *op, const char *from, const char *to, const char *eventna
|
|||
|
||||
sal_op_publish_fill_cbs(op);
|
||||
req=sal_op_build_request(op,"PUBLISH");
|
||||
if (sal_op_get_contact(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));
|
||||
sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body);
|
||||
return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher
|
|||
,unsigned int status_code
|
||||
,const char* reason_phrase) {
|
||||
SalOp* op = (SalOp*)user_pointer;
|
||||
SalError sal_err;
|
||||
SalReason sal_reason;
|
||||
belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));
|
||||
ms_message("Register refresher [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op));
|
||||
|
||||
|
|
@ -57,13 +55,12 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher
|
|||
chooses not to re-register, the UA SHOULD discard any stored service
|
||||
route for that address-of-record. */
|
||||
sal_op_set_service_route(op,NULL);
|
||||
|
||||
sal_compute_sal_errors_from_code(status_code,&sal_err,&sal_reason);
|
||||
op->base.root->callbacks.register_failure(op,sal_err,sal_reason,reason_phrase);
|
||||
sal_error_info_set(&op->error_info,SalReasonUnknown,status_code,reason_phrase,NULL);
|
||||
op->base.root->callbacks.register_failure(op);
|
||||
if (op->auth_info) {
|
||||
/*add pending auth*/
|
||||
sal_add_pending_auth(op->base.root,op);
|
||||
if (status_code==403)
|
||||
if (status_code==403 || status_code==401 || status_code==407 )
|
||||
op->base.root->callbacks.auth_failure(op,op->auth_info);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,26 @@ static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const S
|
|||
if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer));
|
||||
}
|
||||
|
||||
static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMediaDescription *md, const SalStreamDescription *stream ) {
|
||||
static belle_sdp_attribute_t * create_rtcp_xr_attribute(const OrtpRtcpXrConfiguration *config) {
|
||||
belle_sdp_rtcp_xr_attribute_t *attribute = belle_sdp_rtcp_xr_attribute_new();
|
||||
if (config->rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
|
||||
if (config->rcvr_rtt_mode == OrtpRtcpXrRcvrRttAll) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "all");
|
||||
else if (config->rcvr_rtt_mode == OrtpRtcpXrRcvrRttSender) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(attribute, "sender");
|
||||
belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_max_size(attribute, config->rcvr_rtt_max_size);
|
||||
}
|
||||
belle_sdp_rtcp_xr_attribute_set_stat_summary(attribute, (config->stat_summary_enabled == TRUE));
|
||||
if (config->stat_summary_enabled == TRUE) {
|
||||
if (config->stat_summary_flags & OrtpRtcpXrStatSummaryLoss) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "loss");
|
||||
if (config->stat_summary_flags & OrtpRtcpXrStatSummaryDup) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "dup");
|
||||
if (config->stat_summary_flags & OrtpRtcpXrStatSummaryJitt) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "jitt");
|
||||
if (config->stat_summary_flags & OrtpRtcpXrStatSummaryTTL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "TTL");
|
||||
if (config->stat_summary_flags & OrtpRtcpXrStatSummaryHL) belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(attribute, "HL");
|
||||
}
|
||||
belle_sdp_rtcp_xr_attribute_set_voip_metrics(attribute, (config->voip_metrics_enabled == TRUE));
|
||||
return BELLE_SDP_ATTRIBUTE(attribute);
|
||||
}
|
||||
|
||||
static void stream_description_to_sdp ( belle_sdp_session_description_t *session_desc, const SalMediaDescription *md, const SalStreamDescription *stream ) {
|
||||
belle_sdp_mime_parameter_t* mime_param;
|
||||
belle_sdp_media_description_t* media_desc;
|
||||
int j;
|
||||
|
|
@ -87,7 +106,7 @@ static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMedia
|
|||
rtp_port=stream->rtp_port;
|
||||
rtcp_port=stream->rtcp_port;
|
||||
|
||||
media_desc = belle_sdp_media_description_create ( sal_stream_type_to_string ( stream->type )
|
||||
media_desc = belle_sdp_media_description_create ( sal_stream_description_get_type_as_string(stream)
|
||||
,stream->rtp_port
|
||||
,1
|
||||
,sal_media_proto_to_string ( stream->proto )
|
||||
|
|
@ -127,28 +146,36 @@ static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMedia
|
|||
if ( stream->proto == SalProtoRtpSavp ) {
|
||||
/* add crypto lines */
|
||||
for ( j=0; j<SAL_CRYPTO_ALGO_MAX; j++ ) {
|
||||
const char *enc_name=NULL;
|
||||
|
||||
switch ( stream->crypto[j].algo ) {
|
||||
case AES_128_SHA1_80:
|
||||
snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s",
|
||||
stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", stream->crypto[j].master_key );
|
||||
belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) );
|
||||
case MS_AES_128_SHA1_80:
|
||||
enc_name="AES_CM_128_HMAC_SHA1_80";
|
||||
break;
|
||||
case AES_128_SHA1_32:
|
||||
snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s",
|
||||
stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", stream->crypto[j].master_key );
|
||||
belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) );
|
||||
case MS_AES_128_SHA1_32:
|
||||
enc_name="AES_CM_128_HMAC_SHA1_32";
|
||||
break;
|
||||
case AES_128_NO_AUTH:
|
||||
case MS_AES_256_SHA1_32:
|
||||
enc_name="AES_CM_256_HMAC_SHA1_32";
|
||||
break;
|
||||
case MS_AES_256_SHA1_80:
|
||||
enc_name="AES_CM_256_HMAC_SHA1_32";
|
||||
break;
|
||||
case MS_AES_128_NO_AUTH:
|
||||
ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" );
|
||||
break;
|
||||
case NO_CIPHER_SHA1_80:
|
||||
case MS_NO_CIPHER_SHA1_80:
|
||||
ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" );
|
||||
break;
|
||||
default:
|
||||
j = SAL_CRYPTO_ALGO_MAX;
|
||||
/* no break */
|
||||
}
|
||||
if (enc_name){
|
||||
snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s",
|
||||
stream->crypto[j].tag, enc_name, stream->crypto[j].master_key );
|
||||
belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
switch ( stream->dir ) {
|
||||
|
|
@ -194,8 +221,29 @@ static belle_sdp_media_description_t *stream_description_to_sdp ( const SalMedia
|
|||
add_ice_remote_candidates(media_desc,stream);
|
||||
}
|
||||
}
|
||||
|
||||
return media_desc;
|
||||
|
||||
if (stream->rtcp_xr.enabled == TRUE) {
|
||||
char sastr[1024] = {0};
|
||||
char mastr[1024] = {0};
|
||||
size_t saoff = 0;
|
||||
size_t maoff = 0;
|
||||
const belle_sdp_attribute_t *session_attribute = belle_sdp_session_description_get_attribute(session_desc, "rtcp-xr");
|
||||
belle_sdp_attribute_t *media_attribute;
|
||||
if (session_attribute != NULL) {
|
||||
belle_sip_object_marshal((belle_sip_object_t*)session_attribute, sastr, sizeof(sastr), &saoff);
|
||||
}
|
||||
media_attribute = create_rtcp_xr_attribute(&stream->rtcp_xr);
|
||||
if (media_attribute != NULL) {
|
||||
belle_sip_object_marshal((belle_sip_object_t*)media_attribute, mastr, sizeof(mastr), &maoff);
|
||||
}
|
||||
if (strcmp(sastr, mastr) != 0) {
|
||||
belle_sdp_media_description_add_attribute(media_desc, media_attribute);
|
||||
} else {
|
||||
belle_sip_object_unref((belle_sip_object_t*)media_attribute);
|
||||
}
|
||||
}
|
||||
|
||||
belle_sdp_session_description_add_media_description(session_desc, media_desc);
|
||||
}
|
||||
|
||||
belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescription *desc ) {
|
||||
|
|
@ -218,7 +266,8 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
|
|||
|
||||
belle_sdp_session_description_set_origin ( session_desc,origin );
|
||||
|
||||
belle_sdp_session_description_set_session_name ( session_desc,belle_sdp_session_name_create ( "Talk" ) );
|
||||
belle_sdp_session_description_set_session_name ( session_desc,
|
||||
belle_sdp_session_name_create ( desc->name[0]!='\0' ? desc->name : "Talk" ) );
|
||||
|
||||
if ( (!sal_media_description_has_dir ( desc,SalStreamSendOnly ) && !sal_media_description_has_dir ( desc,SalStreamInactive ))
|
||||
|| desc->ice_ufrag[0] != '\0' ) {
|
||||
|
|
@ -242,255 +291,342 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr
|
|||
if (desc->ice_completed == 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));
|
||||
|
||||
|
||||
if (desc->rtcp_xr.enabled == TRUE) {
|
||||
belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr));
|
||||
}
|
||||
|
||||
for ( i=0; i<desc->n_total_streams; i++ ) {
|
||||
belle_sdp_session_description_add_media_description ( session_desc,stream_description_to_sdp(desc,&desc->streams[i]));
|
||||
stream_description_to_sdp(session_desc, desc, &desc->streams[i]);
|
||||
}
|
||||
return session_desc;
|
||||
}
|
||||
|
||||
|
||||
static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
|
||||
PayloadType *pt;
|
||||
belle_sip_list_t* mime_param_it=NULL;
|
||||
belle_sdp_mime_parameter_t* mime_param;
|
||||
belle_sip_list_t* mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc );
|
||||
for ( mime_param_it=mime_params
|
||||
; mime_param_it!=NULL
|
||||
; mime_param_it=mime_param_it->next ) {
|
||||
mime_param=BELLE_SDP_MIME_PARAMETER ( mime_param_it->data );
|
||||
|
||||
pt=payload_type_new();
|
||||
payload_type_set_number ( pt,belle_sdp_mime_parameter_get_media_format ( mime_param ) );
|
||||
pt->clock_rate=belle_sdp_mime_parameter_get_rate ( mime_param );
|
||||
pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) );
|
||||
pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param );
|
||||
payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) );
|
||||
stream->payloads=ms_list_append ( stream->payloads,pt );
|
||||
stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param );
|
||||
ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
|
||||
pt->send_fmtp ? pt->send_fmtp : "" );
|
||||
}
|
||||
if ( mime_params ) belle_sip_list_free_with_data ( mime_params,belle_sip_object_unref );
|
||||
}
|
||||
|
||||
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];
|
||||
int valid_count = 0;
|
||||
int nb;
|
||||
|
||||
memset ( &stream->crypto, 0, sizeof ( stream->crypto ) );
|
||||
for ( attribute_it=belle_sdp_media_description_get_attributes ( media_desc )
|
||||
; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL;
|
||||
attribute_it=attribute_it->next ) {
|
||||
attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data );
|
||||
|
||||
if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) {
|
||||
nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s",
|
||||
&stream->crypto[valid_count].tag,
|
||||
tmp,
|
||||
tmp2 );
|
||||
ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'",
|
||||
stream->crypto[valid_count].tag,
|
||||
tmp,
|
||||
tmp2 );
|
||||
if ( nb == 3 ) {
|
||||
if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ){
|
||||
stream->crypto[valid_count].algo = MS_AES_128_SHA1_80;
|
||||
}else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 ){
|
||||
stream->crypto[valid_count].algo = MS_AES_128_SHA1_32;
|
||||
}else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_32",tmp ) == 0 ){
|
||||
stream->crypto[valid_count].algo = MS_AES_256_SHA1_32;
|
||||
}else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_80",tmp ) == 0 ){
|
||||
stream->crypto[valid_count].algo = MS_AES_256_SHA1_80;
|
||||
}else {
|
||||
ms_warning ( "Failed to parse crypto-algo: '%s'", tmp );
|
||||
stream->crypto[valid_count].algo = 0;
|
||||
}
|
||||
if ( stream->crypto[valid_count].algo ) {
|
||||
strncpy ( stream->crypto[valid_count].master_key, tmp2, 41 );
|
||||
stream->crypto[valid_count].master_key[40] = '\0';
|
||||
ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'",
|
||||
stream->crypto[valid_count].tag,
|
||||
tmp,
|
||||
stream->crypto[valid_count].master_key );
|
||||
valid_count++;
|
||||
}
|
||||
} else {
|
||||
ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb );
|
||||
}
|
||||
}
|
||||
}
|
||||
ms_message ( "Found: %d valid crypto lines", valid_count );
|
||||
}
|
||||
|
||||
static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) {
|
||||
belle_sip_list_t *attribute_it;
|
||||
belle_sdp_attribute_t *attribute;
|
||||
const char *att_name;
|
||||
const char *value;
|
||||
int nb_ice_candidates = 0;
|
||||
|
||||
for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) {
|
||||
attribute=BELLE_SDP_ATTRIBUTE(attribute_it->data);
|
||||
att_name = belle_sdp_attribute_get_name(attribute);
|
||||
value = belle_sdp_attribute_get_value(attribute);
|
||||
|
||||
if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) {
|
||||
SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates];
|
||||
int nb = sscanf(value, "%s %u UDP %u %s %d typ %s raddr %s rport %d",
|
||||
candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port,
|
||||
candidate->type, candidate->raddr, &candidate->rport);
|
||||
if ((nb == 6) || (nb == 8)) nb_ice_candidates++;
|
||||
else memset(candidate, 0, sizeof(*candidate));
|
||||
} else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) {
|
||||
SalIceRemoteCandidate candidate;
|
||||
unsigned int componentID;
|
||||
int offset;
|
||||
const char *ptr = value;
|
||||
const char *endptr = value + strlen(ptr);
|
||||
while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) {
|
||||
if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) {
|
||||
SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1];
|
||||
strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)-1);
|
||||
remote_candidate->port = candidate.port;
|
||||
}
|
||||
ptr += offset;
|
||||
if (ptr < endptr) {
|
||||
if (ptr[offset] == ' ') ptr += 1;
|
||||
} else break;
|
||||
}
|
||||
} else if ((keywordcmp("ice-ufrag", att_name) == 0) && (value != NULL)) {
|
||||
strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag)-1);
|
||||
} else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) {
|
||||
strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd) -1);
|
||||
} else if (keywordcmp("ice-mismatch", att_name) == 0) {
|
||||
stream->ice_mismatch = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sal_init_rtcp_xr_description(OrtpRtcpXrConfiguration *config) {
|
||||
config->enabled = FALSE;
|
||||
config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone;
|
||||
config->rcvr_rtt_max_size = -1;
|
||||
config->stat_summary_flags = 0;
|
||||
config->voip_metrics_enabled = FALSE;
|
||||
}
|
||||
|
||||
static void sdp_parse_rtcp_xr_parameters(const belle_sdp_attribute_t *attribute, OrtpRtcpXrConfiguration *config) {
|
||||
if (attribute != NULL) {
|
||||
const belle_sdp_rtcp_xr_attribute_t *xr_attr;
|
||||
const char *rcvr_rtt_mode;
|
||||
sal_init_rtcp_xr_description(config);
|
||||
xr_attr = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute);
|
||||
rcvr_rtt_mode = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(xr_attr);
|
||||
if (rcvr_rtt_mode != NULL) {
|
||||
if (strcasecmp(rcvr_rtt_mode, "all") == 0) {
|
||||
config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttAll;
|
||||
} else if (strcasecmp(rcvr_rtt_mode, "sender") == 0) {
|
||||
config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttSender;
|
||||
}
|
||||
config->rcvr_rtt_max_size = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_max_size(xr_attr);
|
||||
}
|
||||
config->stat_summary_enabled = (belle_sdp_rtcp_xr_attribute_has_stat_summary(xr_attr) != 0);
|
||||
if (config->stat_summary_enabled) {
|
||||
belle_sip_list_t *stat_summary_flag_it;
|
||||
for (stat_summary_flag_it = belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(xr_attr); stat_summary_flag_it != NULL; stat_summary_flag_it = stat_summary_flag_it->next ) {
|
||||
const char *flag = (const char *)stat_summary_flag_it->data;
|
||||
if (flag != NULL) {
|
||||
if (strcasecmp(flag, "loss") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryLoss;
|
||||
else if (strcasecmp(flag, "dup") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryDup;
|
||||
else if (strcasecmp(flag, "jitt") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryJitt;
|
||||
else if (strcasecmp(flag, "TTL") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryTTL;
|
||||
else if (strcasecmp(flag, "HL") == 0) config->stat_summary_flags |= OrtpRtcpXrStatSummaryHL;
|
||||
}
|
||||
}
|
||||
}
|
||||
config->voip_metrics_enabled = (belle_sdp_rtcp_xr_attribute_has_voip_metrics(xr_attr) != 0);
|
||||
config->enabled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void sdp_parse_session_rtcp_xr_parameters(belle_sdp_session_description_t *session_desc, OrtpRtcpXrConfiguration *config) {
|
||||
const belle_sdp_attribute_t *attribute = belle_sdp_session_description_get_attribute(session_desc, "rtcp-xr");
|
||||
sdp_parse_rtcp_xr_parameters(attribute, config);
|
||||
}
|
||||
|
||||
static void sdp_parse_media_rtcp_xr_parameters(belle_sdp_media_description_t *media_desc, OrtpRtcpXrConfiguration *config) {
|
||||
const belle_sdp_attribute_t *attribute = belle_sdp_media_description_get_attribute(media_desc, "rtcp-xr");
|
||||
sdp_parse_rtcp_xr_parameters(attribute, config);
|
||||
}
|
||||
|
||||
static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, belle_sdp_media_description_t *media_desc) {
|
||||
SalStreamDescription *stream;
|
||||
belle_sdp_connection_t* cnx;
|
||||
belle_sdp_media_t* media;
|
||||
belle_sdp_attribute_t* attribute;
|
||||
const char* value;
|
||||
const char *mtype,*proto;
|
||||
|
||||
stream=&md->streams[md->n_total_streams];
|
||||
media=belle_sdp_media_description_get_media ( media_desc );
|
||||
|
||||
memset ( stream,0,sizeof ( *stream ) );
|
||||
|
||||
proto = belle_sdp_media_get_protocol ( media );
|
||||
stream->proto=SalProtoOther;
|
||||
if ( proto ) {
|
||||
if ( strcasecmp ( proto,"RTP/AVP" ) ==0 )
|
||||
stream->proto=SalProtoRtpAvp;
|
||||
else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) {
|
||||
stream->proto=SalProtoRtpSavp;
|
||||
}else{
|
||||
strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1);
|
||||
}
|
||||
}
|
||||
if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
|
||||
strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ), sizeof ( stream->rtp_addr ) -1 );
|
||||
}
|
||||
|
||||
stream->rtp_port=belle_sdp_media_get_media_port ( media );
|
||||
|
||||
if ( stream->rtp_port > 0 )
|
||||
md->n_active_streams++;
|
||||
|
||||
mtype = belle_sdp_media_get_media_type ( media );
|
||||
if ( strcasecmp ( "audio", mtype ) == 0 ) {
|
||||
stream->type=SalAudio;
|
||||
} else if ( strcasecmp ( "video", mtype ) == 0 ) {
|
||||
stream->type=SalVideo;
|
||||
} else {
|
||||
stream->type=SalOther;
|
||||
strncpy ( stream->typeother,mtype,sizeof ( stream->typeother )-1 );
|
||||
}
|
||||
|
||||
if ( belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ) >0 ) {
|
||||
stream->bandwidth=belle_sdp_media_description_get_bandwidth ( media_desc,"AS" );
|
||||
}
|
||||
|
||||
if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) {
|
||||
stream->dir=SalStreamSendRecv;
|
||||
} else if ( belle_sdp_media_description_get_attribute ( media_desc,"sendonly" ) ) {
|
||||
stream->dir=SalStreamSendOnly;
|
||||
} else if ( belle_sdp_media_description_get_attribute ( media_desc,"recvonly" ) ) {
|
||||
stream->dir=SalStreamRecvOnly;
|
||||
} else if ( belle_sdp_media_description_get_attribute ( media_desc,"inactive" ) ) {
|
||||
stream->dir=SalStreamInactive;
|
||||
} else {
|
||||
stream->dir=md->dir; /*takes default value if not present*/
|
||||
}
|
||||
|
||||
/* Get media payload types */
|
||||
sdp_parse_payload_types(media_desc, stream);
|
||||
|
||||
/* Get media specific RTCP attribute */
|
||||
stream->rtcp_port = stream->rtp_port + 1;
|
||||
snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr);
|
||||
attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp");
|
||||
if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
|
||||
char tmp[256];
|
||||
int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp);
|
||||
if (nb == 1) {
|
||||
/* SDP rtcp attribute only contains the port */
|
||||
} else if (nb == 2) {
|
||||
strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)-1);
|
||||
} else {
|
||||
ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read crypto lines if any */
|
||||
if ( stream->proto == SalProtoRtpSavp ) {
|
||||
sdp_parse_media_crypto_parameters(media_desc, stream);
|
||||
}
|
||||
|
||||
/* Get ICE candidate attributes if any */
|
||||
sdp_parse_media_ice_parameters(media_desc, stream);
|
||||
|
||||
/* Get RTCP-XR attributes if any */
|
||||
stream->rtcp_xr = md->rtcp_xr; // Use session parameters if no stream parameters are defined
|
||||
sdp_parse_media_rtcp_xr_parameters(media_desc, &stream->rtcp_xr);
|
||||
|
||||
md->n_total_streams++;
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) {
|
||||
/*
|
||||
typedef struct SalMediaDescription{
|
||||
int refcount;
|
||||
char addr[64];
|
||||
char username[64];
|
||||
int nstreams;
|
||||
int bandwidth;
|
||||
unsigned int session_ver;
|
||||
unsigned int session_id;
|
||||
SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS];
|
||||
} SalMediaDescription;
|
||||
*/
|
||||
belle_sdp_connection_t* cnx;
|
||||
belle_sip_list_t* media_desc_it;
|
||||
belle_sdp_media_description_t* media_desc;
|
||||
const char *mtype,*proto;
|
||||
SalStreamDescription *stream;
|
||||
belle_sdp_media_t* media;
|
||||
belle_sip_list_t* mime_params=NULL;
|
||||
belle_sip_list_t* mime_param_it=NULL;
|
||||
belle_sdp_mime_parameter_t* mime_param;
|
||||
PayloadType *pt;
|
||||
belle_sip_list_t* attribute_it;
|
||||
const belle_sdp_attribute_t* attribute;
|
||||
int valid_count = 0;
|
||||
char tmp[256], tmp2[256];
|
||||
int nb=0;
|
||||
SalStreamDir stream_dir=SalStreamSendRecv;
|
||||
belle_sdp_session_name_t *sname;
|
||||
const char* value;
|
||||
|
||||
desc->n_active_streams = 0;
|
||||
desc->n_total_streams = 0;
|
||||
desc->dir = SalStreamSendRecv;
|
||||
|
||||
if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
|
||||
strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) );
|
||||
strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) -1 );
|
||||
}
|
||||
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" ) ) {
|
||||
stream_dir=SalStreamSendRecv;
|
||||
desc->dir=SalStreamSendRecv;
|
||||
} else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) {
|
||||
stream_dir=SalStreamSendOnly;
|
||||
desc->dir=SalStreamSendOnly;
|
||||
} else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) {
|
||||
stream_dir=SalStreamRecvOnly;
|
||||
desc->dir=SalStreamRecvOnly;
|
||||
} else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) {
|
||||
stream_dir=SalStreamInactive;
|
||||
desc->dir=SalStreamInactive;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
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));
|
||||
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;
|
||||
|
||||
|
||||
/* Get session RTCP-XR attributes if any */
|
||||
sdp_parse_session_rtcp_xr_parameters(session_desc, &desc->rtcp_xr);
|
||||
|
||||
for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc )
|
||||
; media_desc_it!=NULL
|
||||
; media_desc_it=media_desc_it->next ) {
|
||||
int nb_ice_candidates=0;
|
||||
if (desc->n_total_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){
|
||||
ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->n_total_streams);
|
||||
break;
|
||||
}
|
||||
media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data );
|
||||
stream=&desc->streams[desc->n_total_streams];
|
||||
media=belle_sdp_media_description_get_media ( media_desc );
|
||||
|
||||
memset ( stream,0,sizeof ( *stream ) );
|
||||
|
||||
proto = belle_sdp_media_get_protocol ( media );
|
||||
stream->proto=SalProtoUnknown;
|
||||
if ( proto ) {
|
||||
if ( strcasecmp ( proto,"RTP/AVP" ) ==0 )
|
||||
stream->proto=SalProtoRtpAvp;
|
||||
else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) {
|
||||
stream->proto=SalProtoRtpSavp;
|
||||
}
|
||||
}
|
||||
if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) {
|
||||
strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ),sizeof ( stream->rtp_addr ) );
|
||||
}
|
||||
|
||||
stream->rtp_port=belle_sdp_media_get_media_port ( media );
|
||||
|
||||
if ( stream->rtp_port > 0 )
|
||||
desc->n_active_streams++;
|
||||
|
||||
mtype = belle_sdp_media_get_media_type ( media );
|
||||
if ( strcasecmp ( "audio", mtype ) == 0 ) {
|
||||
stream->type=SalAudio;
|
||||
} else if ( strcasecmp ( "video", mtype ) == 0 ) {
|
||||
stream->type=SalVideo;
|
||||
} else {
|
||||
stream->type=SalOther;
|
||||
strncpy ( stream->typeother,mtype,sizeof ( stream->typeother )-1 );
|
||||
}
|
||||
|
||||
if ( belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ) >0 ) {
|
||||
stream->bandwidth=belle_sdp_media_description_get_bandwidth ( media_desc,"AS" );
|
||||
}
|
||||
|
||||
|
||||
if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) {
|
||||
stream->dir=SalStreamSendRecv;
|
||||
} else if ( belle_sdp_media_description_get_attribute ( media_desc,"sendonly" ) ) {
|
||||
stream->dir=SalStreamSendOnly;
|
||||
} else if ( belle_sdp_media_description_get_attribute ( media_desc,"recvonly" ) ) {
|
||||
stream->dir=SalStreamRecvOnly;
|
||||
} else if ( belle_sdp_media_description_get_attribute ( media_desc,"inactive" ) ) {
|
||||
stream->dir=SalStreamInactive;
|
||||
} else {
|
||||
stream->dir=stream_dir; /*takes default value if not present*/
|
||||
}
|
||||
|
||||
/* for each payload type */
|
||||
mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc );
|
||||
for ( mime_param_it=mime_params
|
||||
; mime_param_it!=NULL
|
||||
; mime_param_it=mime_param_it->next ) {
|
||||
mime_param=BELLE_SDP_MIME_PARAMETER ( mime_param_it->data )
|
||||
|
||||
pt=payload_type_new();
|
||||
payload_type_set_number ( pt,belle_sdp_mime_parameter_get_media_format ( mime_param ) );
|
||||
pt->clock_rate=belle_sdp_mime_parameter_get_rate ( mime_param );
|
||||
pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) );
|
||||
pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param );
|
||||
payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) );
|
||||
stream->payloads=ms_list_append ( stream->payloads,pt );
|
||||
stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param );
|
||||
ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate,
|
||||
pt->send_fmtp ? pt->send_fmtp : "" );
|
||||
}
|
||||
if ( mime_params ) belle_sip_list_free_with_data ( mime_params,belle_sip_object_unref );
|
||||
|
||||
|
||||
/* Get media specific RTCP attribute */
|
||||
stream->rtcp_port = stream->rtp_port + 1;
|
||||
snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr);
|
||||
attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp");
|
||||
if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){
|
||||
char tmp[256];
|
||||
int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp);
|
||||
if (nb == 1) {
|
||||
/* SDP rtcp attribute only contains the port */
|
||||
} else if (nb == 2) {
|
||||
strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr));
|
||||
} else {
|
||||
ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb);
|
||||
}
|
||||
}
|
||||
|
||||
/* read crypto lines if any */
|
||||
if ( stream->proto == SalProtoRtpSavp ) {
|
||||
valid_count=0;
|
||||
memset ( &stream->crypto, 0, sizeof ( stream->crypto ) );
|
||||
for ( attribute_it=belle_sdp_media_description_get_attributes ( media_desc )
|
||||
; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL;
|
||||
attribute_it=attribute_it->next ) {
|
||||
attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data );
|
||||
|
||||
if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) {
|
||||
nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s",
|
||||
&stream->crypto[valid_count].tag,
|
||||
tmp,
|
||||
tmp2 );
|
||||
ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'",
|
||||
stream->crypto[valid_count].tag,
|
||||
tmp,
|
||||
tmp2 );
|
||||
if ( nb == 3 ) {
|
||||
if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 )
|
||||
stream->crypto[valid_count].algo = AES_128_SHA1_80;
|
||||
else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 )
|
||||
stream->crypto[valid_count].algo = AES_128_SHA1_32;
|
||||
else {
|
||||
ms_warning ( "Failed to parse crypto-algo: '%s'", tmp );
|
||||
stream->crypto[valid_count].algo = 0;
|
||||
}
|
||||
if ( stream->crypto[valid_count].algo ) {
|
||||
strncpy ( stream->crypto[valid_count].master_key, tmp2, 41 );
|
||||
stream->crypto[valid_count].master_key[40] = '\0';
|
||||
ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'",
|
||||
stream->crypto[valid_count].tag,
|
||||
tmp,
|
||||
stream->crypto[valid_count].master_key );
|
||||
valid_count++;
|
||||
}
|
||||
} else {
|
||||
ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb );
|
||||
}
|
||||
}
|
||||
}
|
||||
ms_message ( "Found: %d valid crypto lines", valid_count );
|
||||
}
|
||||
|
||||
/* Get ICE candidate attributes if any */
|
||||
for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) {
|
||||
const char *att_name;
|
||||
attribute=(belle_sdp_attribute_t*)attribute_it->data;
|
||||
att_name=belle_sdp_attribute_get_name(attribute);
|
||||
value=belle_sdp_attribute_get_value(attribute);
|
||||
if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) {
|
||||
SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates];
|
||||
int nb = sscanf(value, "%s %u UDP %u %s %d typ %s raddr %s rport %d",
|
||||
candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port,
|
||||
candidate->type, candidate->raddr, &candidate->rport);
|
||||
if ((nb == 6) || (nb == 8)) nb_ice_candidates++;
|
||||
else memset(candidate, 0, sizeof(*candidate));
|
||||
} else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) {
|
||||
SalIceRemoteCandidate candidate;
|
||||
unsigned int componentID;
|
||||
int offset;
|
||||
const char *ptr = value;
|
||||
const char *endptr=value+strlen(ptr);
|
||||
while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) {
|
||||
if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) {
|
||||
SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1];
|
||||
strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr));
|
||||
remote_candidate->port = candidate.port;
|
||||
}
|
||||
ptr += offset;
|
||||
if (ptr<endptr){
|
||||
if (ptr[offset] == ' ') ptr += 1;
|
||||
}else break;
|
||||
}
|
||||
} else if ((keywordcmp("ice-ufrag", att_name) == 0) && (value != NULL)) {
|
||||
strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag));
|
||||
} else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) {
|
||||
strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd));
|
||||
} else if (keywordcmp("ice-mismatch", att_name) == 0) {
|
||||
stream->ice_mismatch = TRUE;
|
||||
}
|
||||
}
|
||||
desc->n_total_streams++;
|
||||
sdp_to_stream_description(desc, media_desc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details);
|
||||
static void register_failure(SalOp *op);
|
||||
|
||||
static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) {
|
||||
if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED;
|
||||
|
|
@ -58,14 +58,14 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c
|
|||
rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr;
|
||||
rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr;
|
||||
ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
|
||||
rtp_session_set_remote_addr_full(call->audiostream->ms.session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
|
||||
rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
|
||||
}
|
||||
#ifdef VIDEO_ENABLED
|
||||
if (call->videostream && new_videodesc) {
|
||||
rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr;
|
||||
rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr;
|
||||
ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
|
||||
rtp_session_set_remote_addr_full(call->videostream->ms.session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
|
||||
rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
|
||||
}
|
||||
#else
|
||||
(void)new_videodesc;
|
||||
|
|
@ -74,16 +74,30 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c
|
|||
|
||||
void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){
|
||||
SalMediaDescription *oldmd=call->resultdesc;
|
||||
|
||||
bool_t all_muted=FALSE;
|
||||
bool_t send_ringbacktone=FALSE;
|
||||
|
||||
linphone_core_stop_ringing(lc);
|
||||
if (new_md!=NULL){
|
||||
sal_media_description_ref(new_md);
|
||||
call->media_pending=FALSE;
|
||||
}else{
|
||||
call->media_pending=TRUE;
|
||||
if (!new_md) {
|
||||
ms_error("linphone_core_update_streams() called with null media description");
|
||||
return;
|
||||
}
|
||||
if (call->biggestdesc==NULL || new_md->n_total_streams>call->biggestdesc->n_total_streams){
|
||||
/*we have been offered and now are ready to proceed, or we added a new stream*/
|
||||
/*store the media description to remember the mapping of calls*/
|
||||
if (call->biggestdesc){
|
||||
sal_media_description_unref(call->biggestdesc);
|
||||
call->biggestdesc=NULL;
|
||||
}
|
||||
if (sal_call_is_offerer(call->op))
|
||||
call->biggestdesc=sal_media_description_ref(call->localdesc);
|
||||
else
|
||||
call->biggestdesc=sal_media_description_ref(sal_call_get_remote_media_description(call->op));
|
||||
}
|
||||
sal_media_description_ref(new_md);
|
||||
call->expect_media_in_ack=FALSE;
|
||||
call->resultdesc=new_md;
|
||||
if ((call->audiostream && call->audiostream->ms.ticker) || (call->videostream && call->videostream->ms.ticker)){
|
||||
if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){
|
||||
/* we already started media: check if we really need to restart it*/
|
||||
if (oldmd){
|
||||
int md_changed = media_parameters_changed(call, oldmd, new_md);
|
||||
|
|
@ -98,10 +112,11 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
|
|||
if (call->audiostream)
|
||||
linphone_core_enable_mic(lc, linphone_core_mic_enabled(lc));
|
||||
#ifdef VIDEO_ENABLED
|
||||
if (call->videostream && call->camera_active)
|
||||
if (call->videostream && call->camera_enabled)
|
||||
video_stream_change_camera(call->videostream,lc->video_conf.device );
|
||||
#endif
|
||||
}
|
||||
/*FIXME ZRTP, might be restarted in any cases ? */
|
||||
ms_message("No need to restart streams, SDP is unchanged.");
|
||||
goto end;
|
||||
}else {
|
||||
|
|
@ -121,23 +136,17 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
|
|||
linphone_call_init_media_streams (call);
|
||||
}
|
||||
|
||||
if (new_md) {
|
||||
bool_t all_muted=FALSE;
|
||||
bool_t send_ringbacktone=FALSE;
|
||||
|
||||
if (call->audiostream==NULL){
|
||||
/*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/
|
||||
linphone_call_init_media_streams (call);
|
||||
}
|
||||
if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){
|
||||
send_ringbacktone=TRUE;
|
||||
}
|
||||
if (call->state==LinphoneCallIncomingEarlyMedia ||
|
||||
(call->state==LinphoneCallOutgoingEarlyMedia && !call->params.real_early_media)){
|
||||
all_muted=TRUE;
|
||||
}
|
||||
linphone_call_start_media_streams(call,all_muted,send_ringbacktone);
|
||||
if (call->audiostream==NULL){
|
||||
/*this happens after pausing the call locally. The streams are destroyed and then we wait the 200Ok to recreate them*/
|
||||
linphone_call_init_media_streams (call);
|
||||
}
|
||||
if (call->state==LinphoneCallIncomingEarlyMedia && linphone_core_get_remote_ringback_tone (lc)!=NULL){
|
||||
send_ringbacktone=TRUE;
|
||||
}
|
||||
if ((call->state==LinphoneCallIncomingEarlyMedia || call->state==LinphoneCallOutgoingEarlyMedia) && !call->params.real_early_media){
|
||||
all_muted=TRUE;
|
||||
}
|
||||
linphone_call_start_media_streams(call,all_muted,send_ringbacktone);
|
||||
if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){
|
||||
linphone_core_play_named_tone(lc,LinphoneToneCallOnHold);
|
||||
}
|
||||
|
|
@ -196,7 +205,8 @@ static void call_received(SalOp *h){
|
|||
const char *from,*to;
|
||||
char *alt_contact;
|
||||
LinphoneAddress *from_addr, *to_addr;
|
||||
bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",TRUE);
|
||||
/*this mode is deprcated because probably useless*/
|
||||
bool_t prevent_colliding_calls=lp_config_get_int(lc->config,"sip","prevent_colliding_calls",FALSE);
|
||||
|
||||
/* first check if we can answer successfully to this invite */
|
||||
if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) {
|
||||
|
|
@ -363,7 +373,7 @@ static void call_accepted(SalOp *op){
|
|||
linphone_core_update_streams (lc,call,md);
|
||||
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
|
||||
if (call->refer_pending)
|
||||
linphone_core_start_refered_call(lc,call);
|
||||
linphone_core_start_refered_call(lc,call,NULL);
|
||||
}else if (sal_media_description_has_dir(md,SalStreamRecvOnly)){
|
||||
/*we are put on hold when the call is initially accepted */
|
||||
if (lc->vtable.display_status){
|
||||
|
|
@ -397,7 +407,8 @@ static void call_accepted(SalOp *op){
|
|||
linphone_call_fix_call_parameters(call);
|
||||
if (!call->current_params.in_conference)
|
||||
lc->current_call=call;
|
||||
linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
|
||||
if (call->prevstate != LinphoneCallIncomingEarlyMedia) /*don't change state in aswer to a SIP UPDATE in early media*/
|
||||
linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
|
||||
}
|
||||
}else{
|
||||
/*send a bye*/
|
||||
|
|
@ -413,10 +424,10 @@ static void call_ack(SalOp *op){
|
|||
ms_warning("No call to be ACK'd");
|
||||
return ;
|
||||
}
|
||||
if (call->media_pending){
|
||||
if (call->expect_media_in_ack){
|
||||
SalMediaDescription *md=sal_call_get_final_media_description(op);
|
||||
if (md && !sal_media_description_empty(md)){
|
||||
linphone_core_update_streams (lc,call,md);
|
||||
linphone_core_update_streams(lc,call,md);
|
||||
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
|
||||
}else{
|
||||
/*send a bye*/
|
||||
|
|
@ -430,7 +441,7 @@ static void call_ack(SalOp *op){
|
|||
static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){
|
||||
SalMediaDescription *md;
|
||||
SalMediaDescription *rmd=sal_call_get_remote_media_description(call->op);
|
||||
if ((rmd!=NULL) && (call->ice_session!=NULL)) {
|
||||
if (rmd!=NULL && call->ice_session!=NULL) {
|
||||
linphone_core_update_ice_from_remote_media_description(call,rmd);
|
||||
linphone_core_update_local_media_description_from_ice(call->localdesc,call->ice_session);
|
||||
}
|
||||
|
|
@ -463,7 +474,7 @@ static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
|
|||
linphone_call_set_state (call,LinphoneCallPausedByRemote,"Call paused by remote");
|
||||
}
|
||||
|
||||
static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call){
|
||||
static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call,bool_t notify_application){
|
||||
/*first check if media capabilities are compatible*/
|
||||
SalMediaDescription* md;
|
||||
linphone_call_make_local_media_description(lc,call);
|
||||
|
|
@ -474,16 +485,21 @@ static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call){
|
|||
return;
|
||||
}
|
||||
|
||||
if(lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,_("Call is updated by remote."));
|
||||
call->defer_update=FALSE;
|
||||
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
|
||||
if (call->defer_update==FALSE){
|
||||
linphone_core_accept_call_update(lc,call,NULL);
|
||||
if (notify_application) {
|
||||
if(lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,_("Call is updated by remote."));
|
||||
call->defer_update=FALSE;
|
||||
linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote");
|
||||
if (call->defer_update==FALSE){
|
||||
linphone_core_accept_call_update(lc,call,NULL);
|
||||
}
|
||||
} else { /*SIP UPDATE case*/
|
||||
/*can be call from any state*/
|
||||
_linphone_core_accept_call_update(lc,call,NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* this callback is called when an incoming re-INVITE modifies the session*/
|
||||
/* this callback is called when an incoming re-INVITE/ SIP UPDATE modifies the session*/
|
||||
static void call_updating(SalOp *op){
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
|
||||
|
|
@ -492,7 +508,7 @@ static void call_updating(SalOp *op){
|
|||
if (rmd==NULL){
|
||||
/* case of a reINVITE without SDP */
|
||||
call_accept_update(lc,call);
|
||||
call->media_pending=TRUE;
|
||||
call->expect_media_in_ack=TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -502,12 +518,16 @@ static void call_updating(SalOp *op){
|
|||
call_resumed(lc,call);
|
||||
}else call_paused_by_remote(lc,call);
|
||||
break;
|
||||
/*SIP UPDATE CASE*/
|
||||
case LinphoneCallOutgoingEarlyMedia:
|
||||
call_updated_by_remote(lc,call,FALSE);
|
||||
break;
|
||||
case LinphoneCallStreamsRunning:
|
||||
case LinphoneCallConnected:
|
||||
if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){
|
||||
call_paused_by_remote(lc,call);
|
||||
}else{
|
||||
call_updated_by_remote(lc,call);
|
||||
call_updated_by_remote(lc,call,TRUE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -529,14 +549,14 @@ static void call_terminated(SalOp *op, const char *from){
|
|||
break;
|
||||
case LinphoneCallIncomingReceived:
|
||||
case LinphoneCallIncomingEarlyMedia:
|
||||
call->reason=LinphoneReasonNotAnswered;
|
||||
sal_error_info_set(&call->non_op_error,SalReasonRequestTimeout,0,"Incoming call cancelled",NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ms_message("Current call terminated...");
|
||||
if (call->refer_pending){
|
||||
linphone_core_start_refered_call(lc,call);
|
||||
linphone_core_start_refered_call(lc,call,NULL);
|
||||
}
|
||||
//we stop the call only if we have this current call or if we are in call
|
||||
if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) {
|
||||
|
|
@ -555,14 +575,32 @@ static void call_terminated(SalOp *op, const char *from){
|
|||
linphone_call_set_state(call, LinphoneCallEnd,"Call ended");
|
||||
}
|
||||
|
||||
static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){
|
||||
static int resume_call_after_failed_transfer(LinphoneCall *call){
|
||||
ms_message("!!!!!!!!!!resume_call_after_failed_transfer");
|
||||
if (call->was_automatically_paused && call->state==LinphoneCallPausing)
|
||||
return BELLE_SIP_CONTINUE; /*was still in pausing state*/
|
||||
|
||||
if (call->was_automatically_paused && call->state==LinphoneCallPaused){
|
||||
if (sal_op_is_idle(call->op)){
|
||||
linphone_core_resume_call(call->core,call);
|
||||
}else {
|
||||
ms_message("!!!!!!!!!!resume_call_after_failed_transfer, salop was busy");
|
||||
return BELLE_SIP_CONTINUE;
|
||||
}
|
||||
}
|
||||
linphone_call_unref(call);
|
||||
return BELLE_SIP_STOP;
|
||||
}
|
||||
|
||||
static void call_failure(SalOp *op){
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
const SalErrorInfo *ei=sal_op_get_error_info(op);
|
||||
char *msg486=_("User is busy.");
|
||||
char *msg480=_("User is temporarily unavailable.");
|
||||
/*char *retrymsg=_("%s. Retry after %i minute(s).");*/
|
||||
char *msg600=_("User does not want to be disturbed.");
|
||||
char *msg603=_("Call declined.");
|
||||
const char *msg=details;
|
||||
const char *msg=ei->full_string;
|
||||
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
|
||||
LinphoneCall *referer=call->referer;
|
||||
|
||||
|
|
@ -572,83 +610,94 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
|
|||
}
|
||||
|
||||
if (lc->vtable.show) lc->vtable.show(lc);
|
||||
|
||||
if (error==SalErrorNoResponse){
|
||||
msg=_("No response.");
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg);
|
||||
}else if (error==SalErrorProtocol){
|
||||
msg=details ? details : _("Protocol error.");
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc, msg);
|
||||
}else if (error==SalErrorFailure){
|
||||
switch(sr){
|
||||
case SalReasonDeclined:
|
||||
msg=msg603;
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg603);
|
||||
break;
|
||||
case SalReasonBusy:
|
||||
msg=msg486;
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg486);
|
||||
break;
|
||||
case SalReasonRedirect:
|
||||
msg=_("Redirected");
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg);
|
||||
break;
|
||||
case SalReasonTemporarilyUnavailable:
|
||||
msg=msg480;
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg480);
|
||||
break;
|
||||
case SalReasonNotFound:
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg);
|
||||
break;
|
||||
case SalReasonDoNotDisturb:
|
||||
msg=msg600;
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg600);
|
||||
break;
|
||||
case SalReasonMedia:
|
||||
//media_encryption_mandatory
|
||||
if (call->params.media_encryption == LinphoneMediaEncryptionSRTP &&
|
||||
!linphone_core_is_media_encryption_mandatory(lc)) {
|
||||
int i;
|
||||
ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call);
|
||||
linphone_call_stop_media_streams(call);
|
||||
if ( call->state==LinphoneCallOutgoingInit
|
||||
|| call->state==LinphoneCallOutgoingProgress
|
||||
|| call->state==LinphoneCallOutgoingRinging /*push case*/
|
||||
|| call->state==LinphoneCallOutgoingEarlyMedia){
|
||||
ms_message("Retrying call [%p] with AVP",call);
|
||||
/* clear SRTP local params */
|
||||
call->params.media_encryption = LinphoneMediaEncryptionNone;
|
||||
for(i=0; i<call->localdesc->n_active_streams; i++) {
|
||||
call->localdesc->streams[i].proto = SalProtoRtpAvp;
|
||||
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
|
||||
}
|
||||
linphone_core_restart_invite(lc, call);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(ei->reason){
|
||||
case SalReasonNone:
|
||||
break;
|
||||
case SalReasonRequestTimeout:
|
||||
msg=_("Request timeout.");
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg);
|
||||
break;
|
||||
case SalReasonDeclined:
|
||||
msg=msg603;
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg603);
|
||||
break;
|
||||
case SalReasonBusy:
|
||||
msg=msg486;
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg486);
|
||||
break;
|
||||
case SalReasonRedirect:
|
||||
{
|
||||
linphone_call_stop_media_streams(call);
|
||||
if ( call->state==LinphoneCallOutgoingInit
|
||||
|| call->state==LinphoneCallOutgoingProgress
|
||||
|| call->state==LinphoneCallOutgoingRinging /*push case*/
|
||||
|| call->state==LinphoneCallOutgoingEarlyMedia){
|
||||
LinphoneAddress* redirection_to = (LinphoneAddress*)sal_op_get_remote_contact_address(call->op);
|
||||
if( redirection_to ){
|
||||
char* url = linphone_address_as_string(redirection_to);
|
||||
ms_warning("Redirecting call [%p] to %s",call, url);
|
||||
ms_free(url);
|
||||
linphone_call_create_op(call);
|
||||
linphone_core_start_invite(lc, call, redirection_to);
|
||||
return;
|
||||
}
|
||||
msg=_("Incompatible media parameters.");
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg);
|
||||
break;
|
||||
case SalReasonRequestPending:
|
||||
/*restore previous state, the application will decide to resubmit the action if relevant*/
|
||||
call->reason=linphone_reason_from_sal(sr);
|
||||
linphone_call_set_state(call,call->prevstate,msg);
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,_("Call failed."));
|
||||
}
|
||||
msg=_("Redirected");
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg);
|
||||
}
|
||||
break;
|
||||
case SalReasonTemporarilyUnavailable:
|
||||
msg=msg480;
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg480);
|
||||
break;
|
||||
case SalReasonNotFound:
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg);
|
||||
break;
|
||||
case SalReasonDoNotDisturb:
|
||||
msg=msg600;
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg600);
|
||||
break;
|
||||
case SalReasonUnsupportedContent: /*<this is for compatibility: linphone sent 415 because of SDP offer answer failure*/
|
||||
case SalReasonNotAcceptable:
|
||||
//media_encryption_mandatory
|
||||
if (call->params.media_encryption == LinphoneMediaEncryptionSRTP &&
|
||||
!linphone_core_is_media_encryption_mandatory(lc)) {
|
||||
int i;
|
||||
ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call);
|
||||
if (call->state==LinphoneCallOutgoingInit
|
||||
|| call->state==LinphoneCallOutgoingProgress
|
||||
|| call->state==LinphoneCallOutgoingRinging /*push case*/
|
||||
|| call->state==LinphoneCallOutgoingEarlyMedia){
|
||||
ms_message("Retrying call [%p] with AVP",call);
|
||||
/* clear SRTP local params */
|
||||
call->params.media_encryption = LinphoneMediaEncryptionNone;
|
||||
for(i=0; i<call->localdesc->n_active_streams; i++) {
|
||||
call->localdesc->streams[i].proto = SalProtoRtpAvp;
|
||||
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
|
||||
}
|
||||
linphone_core_restart_invite(lc, call);
|
||||
return;
|
||||
}
|
||||
}
|
||||
msg=_("Incompatible media parameters.");
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,msg);
|
||||
break;
|
||||
case SalReasonRequestPending:
|
||||
/*restore previous state, the application will decide to resubmit the action if relevant*/
|
||||
linphone_call_set_state(call,call->prevstate,msg);
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
if (lc->vtable.display_status)
|
||||
lc->vtable.display_status(lc,_("Call failed."));
|
||||
}
|
||||
|
||||
/*some call error are not fatal*/
|
||||
|
|
@ -657,8 +706,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
|
|||
case LinphoneCallPausing:
|
||||
case LinphoneCallResuming:
|
||||
ms_message("Call error on state [%s], restoring previous state",linphone_call_state_to_string(call->prevstate));
|
||||
call->reason=linphone_reason_from_sal(sr);
|
||||
linphone_call_set_state(call, call->prevstate,details);
|
||||
linphone_call_set_state(call, call->prevstate,ei->full_string);
|
||||
return;
|
||||
default:
|
||||
break; /*nothing to do*/
|
||||
|
|
@ -671,29 +719,20 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
|
|||
linphone_call_delete_upnp_session(call);
|
||||
#endif //BUILD_UPNP
|
||||
|
||||
call->reason=linphone_reason_from_sal(sr);
|
||||
if (sr==SalReasonDeclined){
|
||||
linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
|
||||
}else{
|
||||
linphone_call_set_state(call,LinphoneCallError,details);
|
||||
if (sr==SalReasonBusy)
|
||||
linphone_core_play_named_tone(lc,LinphoneToneBusy);
|
||||
if (call->state!=LinphoneCallEnd && call->state!=LinphoneCallError){
|
||||
if (ei->reason==SalReasonDeclined){
|
||||
linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
|
||||
}else{
|
||||
linphone_call_set_state(call,LinphoneCallError,ei->full_string);
|
||||
}
|
||||
if (ei->reason!=SalReasonNone) linphone_core_play_call_error_tone(lc,linphone_reason_from_sal(ei->reason));
|
||||
}
|
||||
|
||||
if (referer){
|
||||
/*
|
||||
* 1- resume call automatically if we had to pause it before to execute the transfer
|
||||
* 2- notify other party of the transfer faillure
|
||||
* This must be done at the end because transferer call can't be resumed until transfer-target call is changed to error state.
|
||||
* This must be done in this order because if the notify transaction will prevent the resume transaction to take place.
|
||||
* On the contrary, the notify transaction is queued and then executed after the resume completes.
|
||||
**/
|
||||
if (linphone_call_get_state(referer)==LinphoneCallPaused && referer->was_automatically_paused){
|
||||
/*resume to the call that send us the refer automatically*/
|
||||
linphone_core_resume_call(lc,referer);
|
||||
referer->was_automatically_paused=FALSE;
|
||||
}
|
||||
/*notify referer of the failure*/
|
||||
linphone_core_notify_refer_state(lc,referer,call);
|
||||
/*schedule automatic resume of the call. This must be done only after the notifications are completed due to dialog serialization of requests.*/
|
||||
linphone_core_queue_task(lc,(belle_sip_source_func_t)resume_call_after_failed_transfer,linphone_call_ref(referer),"Automatic call resuming after failed transfer");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -709,10 +748,12 @@ static void auth_failure(SalOp *op, SalAuthInfo* info) {
|
|||
LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain);
|
||||
if (ai){
|
||||
ms_message("%s/%s/%s authentication fails.",info->realm,info->username,info->domain);
|
||||
/*ask again for password if auth info was already supplied but apparently not working*/
|
||||
if (lc->vtable.auth_info_requested) {
|
||||
lc->vtable.auth_info_requested(lc,info->realm,info->username,info->domain);
|
||||
}
|
||||
}
|
||||
if (lc->vtable.auth_info_requested) {
|
||||
lc->vtable.auth_info_requested(lc,info->realm,info->username,info->domain);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void register_success(SalOp *op, bool_t registered){
|
||||
|
|
@ -724,9 +765,8 @@ static void register_success(SalOp *op, bool_t registered){
|
|||
ms_message("Registration success for removed proxy config, ignored");
|
||||
return;
|
||||
}
|
||||
linphone_proxy_config_set_error(cfg,LinphoneReasonNone);
|
||||
linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared ,
|
||||
registered ? "Registration sucessful" : "Unregistration done");
|
||||
registered ? "Registration successful" : "Unregistration done");
|
||||
if (lc->vtable.display_status){
|
||||
if (registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
|
||||
else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
|
||||
|
|
@ -736,9 +776,11 @@ static void register_success(SalOp *op, bool_t registered){
|
|||
|
||||
}
|
||||
|
||||
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
|
||||
static void register_failure(SalOp *op){
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
|
||||
const SalErrorInfo *ei=sal_op_get_error_info(op);
|
||||
const char *details=ei->full_string;
|
||||
|
||||
if (cfg==NULL){
|
||||
ms_warning("Registration failed for unknown proxy config.");
|
||||
|
|
@ -752,15 +794,12 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const
|
|||
details=_("no response timeout");
|
||||
|
||||
if (lc->vtable.display_status) {
|
||||
char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details );
|
||||
char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op), details);
|
||||
lc->vtable.display_status(lc,msg);
|
||||
ms_free(msg);
|
||||
}
|
||||
|
||||
linphone_proxy_config_set_error(cfg,linphone_reason_from_sal(reason));
|
||||
|
||||
if (error== SalErrorFailure
|
||||
&& reason == SalReasonServiceUnavailable
|
||||
if ((ei->reason == SalReasonServiceUnavailable || ei->reason == SalReasonIOError)
|
||||
&& linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) {
|
||||
linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying"));
|
||||
} else {
|
||||
|
|
@ -808,14 +847,7 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){
|
|||
lc->vtable.display_status(lc,msg);
|
||||
ms_free(msg);
|
||||
}
|
||||
if (call->state!=LinphoneCallPaused){
|
||||
ms_message("Automatically pausing current call to accept transfer.");
|
||||
_linphone_core_pause_call(lc,call);
|
||||
call->was_automatically_paused=TRUE;
|
||||
/*then we will start the refered when the pause is accepted, in order to serialize transactions within the dialog.
|
||||
* Indeed we need to avoid to send a NOTIFY to inform about of state of the refered call while the pause isn't completed.
|
||||
**/
|
||||
}else linphone_core_start_refered_call(lc,call);
|
||||
if (call->refer_pending) linphone_core_start_refered_call(lc,call,NULL);
|
||||
}else if (lc->vtable.refer_received){
|
||||
lc->vtable.refer_received(lc,referto);
|
||||
}
|
||||
|
|
@ -845,9 +877,17 @@ static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){
|
|||
|
||||
static void text_received(SalOp *op, const SalMessage *msg){
|
||||
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
if (is_duplicate_msg(lc,msg->message_id)==FALSE){
|
||||
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
|
||||
if (lc->chat_deny_code==LinphoneReasonNone && is_duplicate_msg(lc,msg->message_id)==FALSE){
|
||||
linphone_core_message_received(lc,op,msg);
|
||||
}
|
||||
sal_message_reply(op,linphone_reason_to_sal(lc->chat_deny_code));
|
||||
if (!call) sal_op_release(op);
|
||||
}
|
||||
|
||||
static void is_composing_received(SalOp *op, const SalIsComposing *is_composing) {
|
||||
LinphoneCore *lc = (LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
|
||||
linphone_core_is_composing_received(lc, op, is_composing);
|
||||
}
|
||||
|
||||
static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) {
|
||||
|
|
@ -888,25 +928,9 @@ static void ping_reply(SalOp *op){
|
|||
}
|
||||
}
|
||||
|
||||
static const char *get_client_cert_path(LinphoneCore *lc) {
|
||||
static char cldir[200] = {0};
|
||||
#ifdef HAVE_GETENV
|
||||
if (!cldir[0]) {
|
||||
static char default_path[200] = {0};
|
||||
snprintf(default_path, sizeof(default_path), "%s%s", getenv("HOME"), "/linphone_certs");
|
||||
snprintf(cldir, sizeof(cldir), "%s", lp_config_get_string(lc->config,"sip","client_certificates_dir", default_path));
|
||||
}
|
||||
#endif
|
||||
return cldir;
|
||||
}
|
||||
static bool_t fill_auth_info_with_client_certificate(LinphoneCore *lc, SalAuthInfo* sai) {
|
||||
char chain_file[200];
|
||||
char key_file[200];
|
||||
const char *path = get_client_cert_path(lc);
|
||||
|
||||
snprintf(chain_file, sizeof(chain_file), "%s%s", path, "/chain.pem");
|
||||
|
||||
snprintf(key_file, sizeof(key_file), "%s%s", path, "/key.pem");
|
||||
const char *chain_file = lp_config_get_string(lc->config,"sip","client_cert_chain", 0);
|
||||
const char *key_file = lp_config_get_string(lc->config,"sip","client_cert_key", 0);;
|
||||
|
||||
#ifndef WIN32
|
||||
{
|
||||
|
|
@ -934,8 +958,6 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) {
|
|||
sai->userid=ms_strdup(ai->userid?ai->userid:ai->username);
|
||||
sai->password=ai->passwd?ms_strdup(ai->passwd):NULL;
|
||||
sai->ha1=ai->ha1?ms_strdup(ai->ha1):NULL;
|
||||
ai->usecount++;
|
||||
ai->last_use_time=ms_time(NULL);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
|
|
@ -1002,14 +1024,14 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus sta
|
|||
return LinphoneChatMessageStateIdle;
|
||||
}
|
||||
|
||||
static int op_equals(LinphoneCall *a, SalOp *b) {
|
||||
return a->op !=b; /*return 0 if equals*/
|
||||
}
|
||||
|
||||
static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
|
||||
LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op);
|
||||
const MSList* calls = linphone_core_get_calls(chat_msg->chat_room->lc);
|
||||
|
||||
|
||||
if (chat_msg == NULL) {
|
||||
// Do not handle delivery status for isComposing messages.
|
||||
return;
|
||||
}
|
||||
|
||||
chat_msg->state=chatStatusSal2Linphone(status);
|
||||
linphone_chat_message_store_state(chat_msg);
|
||||
if (chat_msg && chat_msg->cb) {
|
||||
|
|
@ -1020,11 +1042,6 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
|
|||
}
|
||||
if (status != SalTextDeliveryInProgress) { /*don't release op if progress*/
|
||||
linphone_chat_message_destroy(chat_msg);
|
||||
|
||||
if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) {
|
||||
/*op was only create for messaging purpose, destroying*/
|
||||
sal_op_release(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1033,8 +1050,9 @@ static void info_received(SalOp *op, const SalBody *body){
|
|||
linphone_core_notify_info_message(lc,op,body);
|
||||
}
|
||||
|
||||
static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason){
|
||||
static void subscribe_response(SalOp *op, SalSubscribeStatus status){
|
||||
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
|
||||
const SalErrorInfo *ei=sal_op_get_error_info(op);
|
||||
|
||||
if (lev==NULL) return;
|
||||
|
||||
|
|
@ -1043,8 +1061,10 @@ static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError er
|
|||
}else if (status==SalSubscribePending){
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionPending);
|
||||
}else{
|
||||
linphone_event_set_reason(lev, linphone_reason_from_sal(reason));
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionError);
|
||||
if (lev->subscription_state==LinphoneSubscriptionActive && ei->reason==SalReasonIOError){
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionOutgoingProgress);
|
||||
}
|
||||
else linphone_event_set_state(lev,LinphoneSubscriptionError);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1085,19 +1105,22 @@ static void subscribe_closed(SalOp *op){
|
|||
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
|
||||
}
|
||||
|
||||
static void on_publish_response(SalOp* op, SalError err, SalReason reason){
|
||||
static void on_publish_response(SalOp* op){
|
||||
LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op);
|
||||
const SalErrorInfo *ei=sal_op_get_error_info(op);
|
||||
|
||||
if (lev==NULL) return;
|
||||
if (err==SalErrorNone){
|
||||
if (ei->reason==SalReasonNone){
|
||||
if (!lev->terminating)
|
||||
linphone_event_set_publish_state(lev,LinphonePublishOk);
|
||||
else
|
||||
linphone_event_set_publish_state(lev,LinphonePublishCleared);
|
||||
|
||||
}else{
|
||||
linphone_event_set_reason(lev,linphone_reason_from_sal(reason));
|
||||
linphone_event_set_publish_state(lev,LinphonePublishError);
|
||||
if (lev->publish_state==LinphonePublishOk){
|
||||
linphone_event_set_publish_state(lev,LinphonePublishProgress);
|
||||
}else{
|
||||
linphone_event_set_publish_state(lev,LinphonePublishError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1108,6 +1131,8 @@ static void on_expire(SalOp *op){
|
|||
|
||||
if (linphone_event_get_publish_state(lev)==LinphonePublishOk){
|
||||
linphone_event_set_publish_state(lev,LinphonePublishExpiring);
|
||||
}else if (linphone_event_get_subscription_state(lev)==LinphoneSubscriptionActive){
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionExpiring);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1128,6 +1153,7 @@ SalCallbacks linphone_sal_callbacks={
|
|||
refer_received,
|
||||
text_received,
|
||||
text_delivery_update,
|
||||
is_composing_received,
|
||||
notify_refer,
|
||||
subscribe_received,
|
||||
subscribe_closed,
|
||||
|
|
|
|||
338
coreapi/chat.c
338
coreapi/chat.c
|
|
@ -26,11 +26,54 @@
|
|||
#include "private.h"
|
||||
#include "lpconfig.h"
|
||||
|
||||
#include <libxml/xmlwriter.h>
|
||||
|
||||
#define COMPOSING_DEFAULT_IDLE_TIMEOUT 15
|
||||
#define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60
|
||||
#define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120
|
||||
|
||||
static void _linphone_chat_message_destroy(LinphoneChatMessage* msg);
|
||||
|
||||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessage);
|
||||
|
||||
BELLE_SIP_INSTANCIATE_VPTR(LinphoneChatMessage,belle_sip_object_t,
|
||||
(belle_sip_object_destroy_t)_linphone_chat_message_destroy,
|
||||
NULL, // clone
|
||||
NULL, // marshal
|
||||
FALSE
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup chatroom
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Inconditionnaly disable incoming chat messages.
|
||||
* @param lc the core
|
||||
* @param deny_reason the deny reason (#LinphoneReasonNone has no effect).
|
||||
**/
|
||||
void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason){
|
||||
lc->chat_deny_code=deny_reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable reception of incoming chat messages.
|
||||
* By default it is enabled but it can be disabled with linphone_core_disable_chat().
|
||||
* @param lc the core
|
||||
**/
|
||||
void linphone_core_enable_chat(LinphoneCore *lc){
|
||||
lc->chat_deny_code=LinphoneReasonNone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether chat is enabled.
|
||||
**/
|
||||
bool_t linphone_core_chat_enabled(const LinphoneCore *lc){
|
||||
return lc->chat_deny_code!=LinphoneReasonNone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of chat rooms
|
||||
* @param lc #LinphoneCore object
|
||||
|
|
@ -85,13 +128,40 @@ LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void linphone_chat_room_delete_composing_idle_timer(LinphoneChatRoom *cr) {
|
||||
if (cr->composing_idle_timer) {
|
||||
sal_cancel_timer(cr->lc->sal, cr->composing_idle_timer);
|
||||
belle_sip_object_unref(cr->composing_idle_timer);
|
||||
cr->composing_idle_timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_chat_room_delete_composing_refresh_timer(LinphoneChatRoom *cr) {
|
||||
if (cr->composing_refresh_timer) {
|
||||
sal_cancel_timer(cr->lc->sal, cr->composing_refresh_timer);
|
||||
belle_sip_object_unref(cr->composing_refresh_timer);
|
||||
cr->composing_refresh_timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_chat_room_delete_remote_composing_refresh_timer(LinphoneChatRoom *cr) {
|
||||
if (cr->remote_composing_refresh_timer) {
|
||||
sal_cancel_timer(cr->lc->sal, cr->remote_composing_refresh_timer);
|
||||
belle_sip_object_unref(cr->remote_composing_refresh_timer);
|
||||
cr->remote_composing_refresh_timer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a LinphoneChatRoom.
|
||||
* @param cr #LinphoneChatRoom object
|
||||
*/
|
||||
void linphone_chat_room_destroy(LinphoneChatRoom *cr){
|
||||
LinphoneCore *lc=cr->lc;
|
||||
linphone_chat_room_delete_composing_idle_timer(cr);
|
||||
linphone_chat_room_delete_composing_refresh_timer(cr);
|
||||
linphone_chat_room_delete_remote_composing_refresh_timer(cr);
|
||||
lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr);
|
||||
linphone_address_destroy(cr->peer_url);
|
||||
ms_free(cr->peer);
|
||||
|
|
@ -116,7 +186,6 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
|
|||
call->state==LinphoneCallPausedByRemote){
|
||||
ms_message("send SIP message through the existing call.");
|
||||
op = call->op;
|
||||
call->pending_message=msg;
|
||||
identity=linphone_core_find_best_identity(cr->lc,linphone_call_get_remote_address(call));
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +197,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
|
|||
identity=linphone_proxy_config_get_identity(proxy);
|
||||
}else identity=linphone_core_get_primary_contact(cr->lc);
|
||||
/*sending out of calls*/
|
||||
op = sal_op_new(cr->lc->sal);
|
||||
msg->op = op = sal_op_new(cr->lc->sal);
|
||||
linphone_configure_op(cr->lc,op,cr->peer_url,msg->custom_headers,lp_config_get_int(cr->lc->config,"sip","chat_msg_with_contact",0));
|
||||
sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/
|
||||
}
|
||||
|
|
@ -142,6 +211,12 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
|
|||
msg->dir=LinphoneChatMessageOutgoing;
|
||||
msg->from=linphone_address_new(identity);
|
||||
msg->storage_id=linphone_chat_message_store(msg);
|
||||
|
||||
if (cr->is_composing == LinphoneIsComposingActive) {
|
||||
cr->is_composing = LinphoneIsComposingIdle;
|
||||
}
|
||||
linphone_chat_room_delete_composing_idle_timer(cr);
|
||||
linphone_chat_room_delete_composing_refresh_timer(cr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -159,7 +234,10 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc,
|
|||
//legacy API
|
||||
if (lc->vtable.text_received!=NULL) lc->vtable.text_received(lc, cr, msg->from, msg->message);
|
||||
if (lc->vtable.message_received!=NULL) lc->vtable.message_received(lc, cr,msg);
|
||||
|
||||
if (cr->lc->vtable.is_composing_received != NULL) {
|
||||
cr->remote_is_composing = LinphoneIsComposingIdle;
|
||||
cr->lc->vtable.is_composing_received(cr->lc, cr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -182,7 +260,6 @@ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAd
|
|||
}
|
||||
|
||||
void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg){
|
||||
|
||||
LinphoneChatRoom *cr=NULL;
|
||||
LinphoneAddress *addr;
|
||||
char *cleanfrom;
|
||||
|
|
@ -225,6 +302,85 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag
|
|||
ms_free(from);
|
||||
}
|
||||
|
||||
static int linphone_chat_room_remote_refresh_composing_expired(void *data, unsigned int revents) {
|
||||
LinphoneChatRoom *cr = (LinphoneChatRoom *)data;
|
||||
belle_sip_object_unref(cr->remote_composing_refresh_timer);
|
||||
cr->remote_composing_refresh_timer = NULL;
|
||||
cr->remote_is_composing = LinphoneIsComposingIdle;
|
||||
if (cr->lc->vtable.is_composing_received != NULL)
|
||||
cr->lc->vtable.is_composing_received(cr->lc, cr);
|
||||
return BELLE_SIP_STOP;
|
||||
}
|
||||
|
||||
static const char *iscomposing_prefix = "/xsi:isComposing";
|
||||
|
||||
static void process_im_is_composing_notification(LinphoneChatRoom *cr, xmlparsing_context_t *xml_ctx) {
|
||||
char xpath_str[MAX_XPATH_LENGTH];
|
||||
xmlXPathObjectPtr iscomposing_object;
|
||||
const char *state_str = NULL;
|
||||
const char *refresh_str = NULL;
|
||||
int refresh_duration = lp_config_get_int(cr->lc->config, "sip", "composing_remote_refresh_timeout", COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT);
|
||||
int i;
|
||||
LinphoneIsComposingState state = LinphoneIsComposingIdle;
|
||||
|
||||
if (linphone_create_xml_xpath_context(xml_ctx) < 0) return;
|
||||
|
||||
xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"xsi", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing");
|
||||
iscomposing_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, iscomposing_prefix);
|
||||
if ((iscomposing_object != NULL) && (iscomposing_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= iscomposing_object->nodesetval->nodeNr; i++) {
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:state", iscomposing_prefix, i);
|
||||
state_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if (state_str == NULL) continue;
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/xsi:refresh", iscomposing_prefix, i);
|
||||
refresh_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
}
|
||||
}
|
||||
|
||||
if (state_str != NULL) {
|
||||
if (strcmp(state_str, "active") == 0) {
|
||||
state = LinphoneIsComposingActive;
|
||||
if (refresh_str != NULL) {
|
||||
refresh_duration = atoi(refresh_str);
|
||||
}
|
||||
if (!cr->remote_composing_refresh_timer) {
|
||||
cr->remote_composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_remote_refresh_composing_expired, cr, refresh_duration * 1000, "composing remote refresh timeout");
|
||||
} else {
|
||||
belle_sip_source_set_timeout(cr->remote_composing_refresh_timer, refresh_duration * 1000);
|
||||
}
|
||||
} else {
|
||||
linphone_chat_room_delete_remote_composing_refresh_timer(cr);
|
||||
}
|
||||
|
||||
cr->remote_is_composing = state;
|
||||
if (cr->lc->vtable.is_composing_received != NULL)
|
||||
cr->lc->vtable.is_composing_received(cr->lc, cr);
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_chat_room_notify_is_composing(LinphoneChatRoom *cr, const char *text) {
|
||||
xmlparsing_context_t *xml_ctx = linphone_xmlparsing_context_new();
|
||||
xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
|
||||
xml_ctx->doc = xmlReadDoc((const unsigned char*)text, 0, NULL, 0);
|
||||
if (xml_ctx->doc != NULL) {
|
||||
process_im_is_composing_notification(cr, xml_ctx);
|
||||
} else {
|
||||
ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer);
|
||||
}
|
||||
linphone_xmlparsing_context_destroy(xml_ctx);
|
||||
}
|
||||
|
||||
void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing) {
|
||||
LinphoneChatRoom *cr = linphone_core_get_or_create_chat_room(lc, is_composing->from);
|
||||
if (cr != NULL) {
|
||||
linphone_chat_room_notify_is_composing(cr, is_composing->text);
|
||||
}
|
||||
}
|
||||
|
||||
bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) {
|
||||
return (cr->remote_is_composing == LinphoneIsComposingActive) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns back pointer to LinphoneCore object.
|
||||
**/
|
||||
|
|
@ -262,7 +418,7 @@ const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr)
|
|||
* @return a new #LinphoneChatMessage
|
||||
*/
|
||||
LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, const char* message) {
|
||||
LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1);
|
||||
LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage);
|
||||
msg->chat_room=(LinphoneChatRoom*)cr;
|
||||
msg->message=message?ms_strdup(message):NULL;
|
||||
msg->is_read=TRUE;
|
||||
|
|
@ -285,7 +441,7 @@ LinphoneChatMessage* linphone_chat_room_create_message_2(
|
|||
LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming) {
|
||||
LinphoneCore *lc=linphone_chat_room_get_lc(cr);
|
||||
|
||||
LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1);
|
||||
LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage);
|
||||
msg->chat_room=(LinphoneChatRoom*)cr;
|
||||
msg->message=message?ms_strdup(message):NULL;
|
||||
msg->external_body_url=external_body_url?ms_strdup(external_body_url):NULL;
|
||||
|
|
@ -319,6 +475,131 @@ void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage*
|
|||
_linphone_chat_room_send_message(cr, msg);
|
||||
}
|
||||
|
||||
static char * linphone_chat_room_create_is_composing_xml(LinphoneChatRoom *cr) {
|
||||
xmlBufferPtr buf;
|
||||
xmlTextWriterPtr writer;
|
||||
int err;
|
||||
char *content = NULL;
|
||||
|
||||
buf = xmlBufferCreate();
|
||||
if (buf == NULL) {
|
||||
ms_error("Error creating the XML buffer");
|
||||
return content;
|
||||
}
|
||||
writer = xmlNewTextWriterMemory(buf, 0);
|
||||
if (writer == NULL) {
|
||||
ms_error("Error creating the XML writer");
|
||||
return content;
|
||||
}
|
||||
|
||||
err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"isComposing", (const xmlChar *)"urn:ietf:params:xml:ns:im-iscomposing");
|
||||
}
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"xsi",
|
||||
NULL, (const xmlChar *)"http://www.w3.org/2001/XMLSchema-instance");
|
||||
}
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xsi", (const xmlChar *)"schemaLocation",
|
||||
NULL, (const xmlChar *)"urn:ietf:params:xml:ns:im-composing iscomposing.xsd");
|
||||
}
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterWriteElement(writer, (const xmlChar *)"state",
|
||||
(cr->is_composing == LinphoneIsComposingActive) ? (const xmlChar *)"active" : (const xmlChar *)"idle");
|
||||
}
|
||||
if ((err >= 0) && (cr->is_composing == LinphoneIsComposingActive)) {
|
||||
char refresh_str[4] = { 0 };
|
||||
int refresh_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_refresh_timeout", COMPOSING_DEFAULT_REFRESH_TIMEOUT);
|
||||
snprintf(refresh_str, sizeof(refresh_str), "%u", refresh_timeout);
|
||||
err = xmlTextWriterWriteElement(writer, (const xmlChar *)"refresh", (const xmlChar *)refresh_str);
|
||||
}
|
||||
if (err >= 0) {
|
||||
/* Close the "isComposing" element. */
|
||||
err = xmlTextWriterEndElement(writer);
|
||||
}
|
||||
if (err >= 0) {
|
||||
err = xmlTextWriterEndDocument(writer);
|
||||
}
|
||||
if (err > 0) {
|
||||
/* xmlTextWriterEndDocument returns the size of the content. */
|
||||
content = ms_strdup((char *)buf->content);
|
||||
}
|
||||
xmlFreeTextWriter(writer);
|
||||
xmlBufferFree(buf);
|
||||
return content;
|
||||
}
|
||||
|
||||
static void linphone_chat_room_send_is_composing_notification(LinphoneChatRoom *cr) {
|
||||
SalOp *op = NULL;
|
||||
LinphoneCall *call;
|
||||
const char *identity = NULL;
|
||||
char *content = NULL;
|
||||
|
||||
if (lp_config_get_int(cr->lc->config, "sip", "chat_use_call_dialogs", 0)) {
|
||||
if ((call = linphone_core_get_call_by_remote_address(cr->lc, cr->peer)) != NULL) {
|
||||
if (call->state == LinphoneCallConnected ||
|
||||
call->state == LinphoneCallStreamsRunning ||
|
||||
call->state == LinphoneCallPaused ||
|
||||
call->state == LinphoneCallPausing ||
|
||||
call->state == LinphoneCallPausedByRemote) {
|
||||
ms_message("send SIP message through the existing call.");
|
||||
op = call->op;
|
||||
identity = linphone_core_find_best_identity(cr->lc, linphone_call_get_remote_address(call));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (op == NULL) {
|
||||
LinphoneProxyConfig *proxy = linphone_core_lookup_known_proxy(cr->lc, cr->peer_url);
|
||||
if (proxy)
|
||||
identity = linphone_proxy_config_get_identity(proxy);
|
||||
else
|
||||
identity = linphone_core_get_primary_contact(cr->lc);
|
||||
/*sending out of calls*/
|
||||
op = sal_op_new(cr->lc->sal);
|
||||
linphone_configure_op(cr->lc, op, cr->peer_url, NULL, lp_config_get_int(cr->lc->config, "sip", "chat_msg_with_contact", 0));
|
||||
}
|
||||
content = linphone_chat_room_create_is_composing_xml(cr);
|
||||
if (content != NULL) {
|
||||
sal_message_send(op, identity, cr->peer, "application/im-iscomposing+xml", content);
|
||||
ms_free(content);
|
||||
}
|
||||
}
|
||||
|
||||
static int linphone_chat_room_stop_composing(void *data, unsigned int revents) {
|
||||
LinphoneChatRoom *cr = (LinphoneChatRoom *)data;
|
||||
cr->is_composing = LinphoneIsComposingIdle;
|
||||
linphone_chat_room_send_is_composing_notification(cr);
|
||||
linphone_chat_room_delete_composing_refresh_timer(cr);
|
||||
belle_sip_object_unref(cr->composing_idle_timer);
|
||||
cr->composing_idle_timer = NULL;
|
||||
return BELLE_SIP_STOP;
|
||||
}
|
||||
|
||||
static int linphone_chat_room_refresh_composing(void *data, unsigned int revents) {
|
||||
LinphoneChatRoom *cr = (LinphoneChatRoom *)data;
|
||||
linphone_chat_room_send_is_composing_notification(cr);
|
||||
return BELLE_SIP_CONTINUE;
|
||||
}
|
||||
|
||||
void linphone_chat_room_compose(LinphoneChatRoom *cr) {
|
||||
int idle_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_idle_timeout", COMPOSING_DEFAULT_IDLE_TIMEOUT);
|
||||
int refresh_timeout = lp_config_get_int(cr->lc->config, "sip", "composing_refresh_timeout", COMPOSING_DEFAULT_REFRESH_TIMEOUT);
|
||||
if (cr->is_composing == LinphoneIsComposingIdle) {
|
||||
cr->is_composing = LinphoneIsComposingActive;
|
||||
linphone_chat_room_send_is_composing_notification(cr);
|
||||
if (!cr->composing_refresh_timer) {
|
||||
cr->composing_refresh_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_refresh_composing, cr, refresh_timeout * 1000, "composing refresh timeout");
|
||||
} else {
|
||||
belle_sip_source_set_timeout(cr->composing_refresh_timer, refresh_timeout * 1000);
|
||||
}
|
||||
if (!cr->composing_idle_timer) {
|
||||
cr->composing_idle_timer = sal_create_timer(cr->lc->sal, linphone_chat_room_stop_composing, cr, idle_timeout * 1000, "composing idle timeout");
|
||||
}
|
||||
}
|
||||
belle_sip_source_set_timeout(cr->composing_idle_timer, idle_timeout * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a #LinphoneChatMessageState as a string.
|
||||
*/
|
||||
|
|
@ -534,16 +815,55 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg)
|
|||
/**
|
||||
* Destroys a LinphoneChatMessage.
|
||||
**/
|
||||
void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
|
||||
void linphone_chat_message_destroy(LinphoneChatMessage* msg){
|
||||
belle_sip_object_unref(msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroys a LinphoneChatMessage.
|
||||
**/
|
||||
static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) {
|
||||
if (msg->op) sal_op_release(msg->op);
|
||||
if (msg->message) ms_free(msg->message);
|
||||
if (msg->external_body_url) ms_free(msg->external_body_url);
|
||||
if (msg->from) linphone_address_destroy(msg->from);
|
||||
if (msg->to) linphone_address_destroy(msg->to);
|
||||
if (msg->custom_headers) sal_custom_header_free(msg->custom_headers);
|
||||
ms_free(msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Acquire a reference to the chat message.
|
||||
* @param msg the chat message
|
||||
* @return the same chat message
|
||||
**/
|
||||
LinphoneChatMessage * linphone_chat_message_ref(LinphoneChatMessage *msg){
|
||||
belle_sip_object_ref(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release reference to the chat message.
|
||||
* @param msg the chat message.
|
||||
**/
|
||||
void linphone_chat_message_unref(LinphoneChatMessage *msg){
|
||||
belle_sip_object_unref(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full details about delivery error of a chat message.
|
||||
* @param msg a LinphoneChatMessage
|
||||
* @return a LinphoneErrorInfo describing the details.
|
||||
**/
|
||||
const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg){
|
||||
return linphone_error_info_from_sal_op(msg->op);
|
||||
}
|
||||
|
||||
LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg) {
|
||||
return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ void linphone_call_add_to_conf(LinphoneCall *call, bool_t muted){
|
|||
LinphoneConference *conf=&lc->conf_ctx;
|
||||
MSAudioEndpoint *ep;
|
||||
call->params.has_video = FALSE;
|
||||
call->camera_active = FALSE;
|
||||
call->camera_enabled = FALSE;
|
||||
ep=ms_audio_endpoint_get_from_stream(call->audiostream,TRUE);
|
||||
ms_audio_conference_add_member(conf->conf,ep);
|
||||
ms_audio_conference_mute_member(conf->conf,ep,muted);
|
||||
|
|
@ -206,6 +206,7 @@ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){
|
|||
lc->current_call=NULL;
|
||||
}
|
||||
/*this will trigger a reINVITE that will later redraw the streams */
|
||||
/*FIXME probably a bit too much to just redraw streams !*/
|
||||
linphone_core_update_call(lc,call,params);
|
||||
linphone_call_params_destroy(params);
|
||||
add_local_endpoint(conf,lc);
|
||||
|
|
|
|||
67
coreapi/contact_providers_priv.h
Normal file
67
coreapi/contact_providers_priv.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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 Library 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.
|
||||
*/
|
||||
|
||||
#ifndef CONTACT_PROVIDERS_PRIV_H
|
||||
#define CONTACT_PROVIDERS_PRIV_H
|
||||
|
||||
#include "private.h"
|
||||
#include "linphonecore.h"
|
||||
|
||||
/* Base for contact search and contact provider */
|
||||
|
||||
struct _LinphoneContactSearch{
|
||||
belle_sip_object_t base;
|
||||
ContactSearchID id;
|
||||
char* predicate;
|
||||
ContactSearchCallback cb;
|
||||
void* data;
|
||||
};
|
||||
|
||||
#define LINPHONE_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneContactSearch)
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneContactSearch)
|
||||
|
||||
|
||||
struct _LinphoneContactProvider {
|
||||
belle_sip_object_t base;
|
||||
LinphoneCore* lc;
|
||||
};
|
||||
|
||||
#define LINPHONE_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneContactProvider)
|
||||
|
||||
typedef LinphoneContactSearch* (*LinphoneContactProviderStartSearchMethod)( LinphoneContactProvider* thiz, const char* predicate, ContactSearchCallback cb, void* data );
|
||||
typedef unsigned int (*LinphoneContactProviderCancelSearchMethod)( LinphoneContactProvider* thiz, LinphoneContactSearch *request );
|
||||
|
||||
BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider,belle_sip_object_t)
|
||||
const char* name; /*!< Name of the contact provider (LDAP, Google, ...) */
|
||||
|
||||
/* pure virtual methods: inheriting objects must implement these */
|
||||
LinphoneContactProviderStartSearchMethod begin_search;
|
||||
LinphoneContactProviderCancelSearchMethod cancel_search;
|
||||
BELLE_SIP_DECLARE_CUSTOM_VPTR_END
|
||||
|
||||
/* LDAP search and contact providers */
|
||||
|
||||
|
||||
#define LINPHONE_LDAP_CONTACT_SEARCH(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactSearch)
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneLDAPContactSearch)
|
||||
|
||||
#define LINPHONE_LDAP_CONTACT_PROVIDER(obj) BELLE_SIP_CAST(obj,LinphoneLDAPContactProvider)
|
||||
|
||||
BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider,LinphoneContactProvider)
|
||||
BELLE_SIP_DECLARE_CUSTOM_VPTR_END
|
||||
|
||||
|
||||
#endif // CONTACT_PROVIDERS_PRIV_H
|
||||
138
coreapi/contactprovider.c
Normal file
138
coreapi/contactprovider.c
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* 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 Library 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 "contact_providers_priv.h"
|
||||
#include "contactprovider.h"
|
||||
#include <linphonecore.h>
|
||||
|
||||
/* ############################ *
|
||||
* LinphoneContactSearchRequest *
|
||||
* ############################ */
|
||||
|
||||
void linphone_contact_search_init(LinphoneContactSearch* obj,
|
||||
const char* predicate,
|
||||
ContactSearchCallback cb,
|
||||
void* cb_data)
|
||||
{
|
||||
static unsigned int request_id_counter = 1;
|
||||
obj->id = request_id_counter++; // unique id
|
||||
obj->predicate = ms_strdup(predicate?predicate:"");
|
||||
obj->cb = cb;
|
||||
obj->data = cb_data;
|
||||
}
|
||||
|
||||
static void linphone_contact_search_destroy( LinphoneContactSearch* req) {
|
||||
if( req->predicate ) ms_free(req->predicate);
|
||||
}
|
||||
|
||||
ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj)
|
||||
{
|
||||
return obj->id;
|
||||
}
|
||||
|
||||
const char*linphone_contact_search_get_predicate(LinphoneContactSearch* obj)
|
||||
{
|
||||
return obj->predicate;
|
||||
}
|
||||
|
||||
void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends)
|
||||
{
|
||||
if( req->cb ) req->cb(req, friends, req->data);
|
||||
}
|
||||
|
||||
int linphone_contact_search_compare(const void* a, const void* b) {
|
||||
LinphoneContactSearch *ra=((LinphoneContactSearch*)a);
|
||||
LinphoneContactSearch *rb=((LinphoneContactSearch*)b);
|
||||
return !(ra->id == rb->id); // return 0 if id is equal, 1 otherwise
|
||||
}
|
||||
|
||||
LinphoneContactSearch*linphone_contact_search_ref(void* obj)
|
||||
{
|
||||
return LINPHONE_CONTACT_SEARCH(belle_sip_object_ref(obj));
|
||||
}
|
||||
|
||||
void linphone_ldap_contact_search_unref(void* obj)
|
||||
{
|
||||
belle_sip_object_unref(obj);
|
||||
}
|
||||
|
||||
LinphoneContactSearch* linphone_contact_search_cast(void* obj)
|
||||
{
|
||||
return LINPHONE_CONTACT_SEARCH(obj);
|
||||
}
|
||||
|
||||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactSearch);
|
||||
|
||||
BELLE_SIP_INSTANCIATE_VPTR(LinphoneContactSearch,belle_sip_object_t,
|
||||
(belle_sip_object_destroy_t)linphone_contact_search_destroy,
|
||||
NULL, // clone
|
||||
NULL, // marshal
|
||||
FALSE
|
||||
);
|
||||
|
||||
|
||||
|
||||
/* ####################### *
|
||||
* LinphoneContactProvider *
|
||||
* ####################### */
|
||||
|
||||
|
||||
void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc){
|
||||
obj->lc = lc;
|
||||
}
|
||||
|
||||
static void contact_provider_destroy(LinphoneContactProvider* obj){
|
||||
(void)obj;
|
||||
}
|
||||
|
||||
LinphoneContactSearch* linphone_contact_provider_begin_search(LinphoneContactProvider* obj, const char* predicate, ContactSearchCallback cb, void* data)
|
||||
{
|
||||
return BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->begin_search( LINPHONE_CONTACT_PROVIDER(obj), predicate, cb, data);
|
||||
}
|
||||
|
||||
unsigned int linphone_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch* request)
|
||||
{
|
||||
return BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->cancel_search( LINPHONE_CONTACT_PROVIDER(obj), request);
|
||||
}
|
||||
|
||||
LinphoneContactProvider* linphone_contact_provider_ref(void* obj)
|
||||
{
|
||||
return LINPHONE_CONTACT_PROVIDER(belle_sip_object_ref(obj));
|
||||
}
|
||||
|
||||
void linphone_contact_provider_unref(void* obj)
|
||||
{
|
||||
belle_sip_object_unref(obj);
|
||||
}
|
||||
|
||||
LinphoneContactProvider*linphone_contact_provider_cast(void* obj)
|
||||
{
|
||||
return LINPHONE_CONTACT_PROVIDER(obj);
|
||||
}
|
||||
|
||||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneContactProvider);
|
||||
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(LinphoneContactProvider)
|
||||
{
|
||||
BELLE_SIP_VPTR_INIT(LinphoneContactProvider,belle_sip_object_t,TRUE),
|
||||
(belle_sip_object_destroy_t) contact_provider_destroy,
|
||||
NULL,/*no clone*/
|
||||
NULL,/*no marshal*/
|
||||
},
|
||||
"",
|
||||
// Pure virtual
|
||||
NULL, /* begin_search -> pure virtual */
|
||||
NULL /* cancel_search -> pure virtual */
|
||||
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
|
||||
43
coreapi/contactprovider.h
Normal file
43
coreapi/contactprovider.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 Library 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 "linphonecore.h"
|
||||
|
||||
/* LinphoneContactSearchRequest */
|
||||
|
||||
void linphone_contact_search_init(LinphoneContactSearch* obj, const char* predicate, ContactSearchCallback cb, void* cb_data);
|
||||
ContactSearchID linphone_contact_search_get_id(LinphoneContactSearch* obj);
|
||||
const char* linphone_contact_search_get_predicate(LinphoneContactSearch* obj);
|
||||
void linphone_contact_search_invoke_cb(LinphoneContactSearch* req, MSList* friends);
|
||||
LinphoneContactSearch* linphone_contact_search_ref(void* obj);
|
||||
void linphone_contact_search_unref(void* obj);
|
||||
LinphoneContactSearch* linphone_contact_search_cast( void*obj );
|
||||
|
||||
/* LinphoneContactProvider */
|
||||
|
||||
void linphone_contact_provider_init(LinphoneContactProvider* obj, LinphoneCore* lc);
|
||||
LinphoneCore* linphone_contact_provider_get_core(LinphoneContactProvider* obj);
|
||||
const char* linphone_contact_provider_get_name(LinphoneContactProvider* obj);
|
||||
LinphoneContactProvider* linphone_contact_provider_ref(void* obj);
|
||||
void linphone_contact_provider_unref(void* obj);
|
||||
LinphoneContactProvider* linphone_contact_provider_cast( void*obj );
|
||||
|
||||
LinphoneContactSearch* linphone_contact_provider_begin_search(LinphoneContactProvider* obj,
|
||||
const char* predicate,
|
||||
ContactSearchCallback cb,
|
||||
void* data);
|
||||
unsigned int linphone_contact_provider_cancel_search(LinphoneContactProvider* obj,
|
||||
LinphoneContactSearch* request);
|
||||
159
coreapi/dict.c
Normal file
159
coreapi/dict.c
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "linphonecore.h"
|
||||
#include "lpconfig.h"
|
||||
#include "private.h"
|
||||
|
||||
#include <belle-sip/belle-sip.h>
|
||||
#include <belle-sip/object.h>
|
||||
#include <belle-sip/dict.h>
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup linphone_dict
|
||||
* @{
|
||||
**/
|
||||
|
||||
|
||||
LinphoneDictionary* linphone_dictionary_new()
|
||||
{
|
||||
return belle_sip_dict_create();
|
||||
}
|
||||
|
||||
LinphoneDictionary* linphone_dictionary_clone(const LinphoneDictionary* src)
|
||||
{
|
||||
LinphoneDictionary* cloned = linphone_dictionary_new();
|
||||
if( cloned ){
|
||||
belle_sip_dict_clone(src, cloned);
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
|
||||
LinphoneDictionary* linphone_dictionary_ref(LinphoneDictionary* obj)
|
||||
{
|
||||
return BELLE_SIP_DICT(belle_sip_object_ref(obj));
|
||||
}
|
||||
|
||||
void linphone_dictionary_unref(LinphoneDictionary *obj)
|
||||
{
|
||||
belle_sip_object_unref(obj);
|
||||
}
|
||||
|
||||
void linphone_dictionary_set_int(LinphoneDictionary* obj, const char* key, int value)
|
||||
{
|
||||
belle_sip_dict_set_int(obj, key, value);
|
||||
}
|
||||
|
||||
int linphone_dictionary_get_int(LinphoneDictionary* obj, const char* key, int default_value)
|
||||
{
|
||||
return belle_sip_dict_get_int(obj, key, default_value);
|
||||
}
|
||||
|
||||
void linphone_dictionary_set_string(LinphoneDictionary* obj, const char* key, const char*value)
|
||||
{
|
||||
belle_sip_dict_set_string(obj, key, value);
|
||||
}
|
||||
|
||||
const char* linphone_dictionary_get_string(LinphoneDictionary* obj, const char* key, const char* default_value)
|
||||
{
|
||||
return belle_sip_dict_get_string(obj, key, default_value);
|
||||
}
|
||||
|
||||
void linphone_dictionary_set_int64(LinphoneDictionary* obj, const char* key, int64_t value)
|
||||
{
|
||||
belle_sip_dict_set_int64(obj, key, value);
|
||||
}
|
||||
|
||||
int64_t linphone_dictionary_get_int64(LinphoneDictionary* obj, const char* key, int64_t default_value)
|
||||
{
|
||||
return belle_sip_dict_get_int64(obj, key, default_value);
|
||||
}
|
||||
|
||||
int linphone_dictionary_remove(LinphoneDictionary* obj, const char* key)
|
||||
{
|
||||
return belle_sip_dict_remove(obj, key);
|
||||
}
|
||||
|
||||
void linphone_dictionary_clear(LinphoneDictionary* obj)
|
||||
{
|
||||
belle_sip_dict_clear(obj);
|
||||
}
|
||||
|
||||
int linphone_dictionary_haskey(const LinphoneDictionary* obj, const char* key)
|
||||
{
|
||||
return belle_sip_dict_haskey(obj, key);
|
||||
}
|
||||
|
||||
void linphone_dictionary_foreach(const LinphoneDictionary* obj, void (*apply_func)(const char*, void*, void*), void* userdata)
|
||||
{
|
||||
return belle_sip_dict_foreach(obj, apply_func, userdata);
|
||||
}
|
||||
|
||||
struct lp_config_to_dict {
|
||||
const char* section;
|
||||
const LpConfig* config;
|
||||
LinphoneDictionary* dict;
|
||||
};
|
||||
|
||||
static void lp_config_section_to_dict_cb(const char*key, struct lp_config_to_dict* userdata)
|
||||
{
|
||||
const char* value = lp_config_get_string(userdata->config, userdata->section, key, "");
|
||||
linphone_dictionary_set_string(userdata->dict, key, value);
|
||||
}
|
||||
|
||||
LinphoneDictionary* lp_config_section_to_dict(const LpConfig* lpconfig, const char* section)
|
||||
{
|
||||
LinphoneDictionary* dict = NULL;
|
||||
struct lp_config_to_dict fd;
|
||||
fd.config = lpconfig;
|
||||
fd.section = section;
|
||||
|
||||
dict = linphone_dictionary_new();
|
||||
fd.dict = dict;
|
||||
|
||||
lp_config_for_each_entry(lpconfig, section,
|
||||
(void (*)(const char*, void*))lp_config_section_to_dict_cb,
|
||||
&fd);
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
struct lp_config_from_dict {
|
||||
const char* section;
|
||||
LpConfig* config;
|
||||
};
|
||||
|
||||
static void lp_config_dict_dump_cb( const char* key, void* value, void* userdata)
|
||||
{
|
||||
struct lp_config_from_dict* fd= (struct lp_config_from_dict*)userdata;
|
||||
lp_config_set_string(fd->config, fd->section, key, (const char*)value);
|
||||
}
|
||||
|
||||
void lp_config_load_dict_to_section(LpConfig* lpconfig, const char* section, const LinphoneDictionary* dict)
|
||||
{
|
||||
struct lp_config_from_dict pvdata = { section, lpconfig };
|
||||
linphone_dictionary_foreach(dict,lp_config_dict_dump_cb, &pvdata);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
**/
|
||||
|
|
@ -154,7 +154,7 @@ static void ecc_play_tones(EcCalibrator *ecc){
|
|||
memset(&tone,0,sizeof(tone));
|
||||
memset(&expected_tone,0,sizeof(expected_tone));
|
||||
|
||||
ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc);
|
||||
ms_filter_add_notify_callback(ecc->det,on_tone_received,ecc,TRUE);
|
||||
|
||||
/* configure the tones to be scanned */
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ static void ecc_play_tones(EcCalibrator *ecc){
|
|||
ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
|
||||
ms_sleep(2);
|
||||
|
||||
ms_filter_set_notify_callback(ecc->gen,on_tone_sent,ecc);
|
||||
ms_filter_add_notify_callback(ecc->gen,on_tone_sent,ecc,TRUE);
|
||||
|
||||
/* play the three tones*/
|
||||
|
||||
|
|
|
|||
148
coreapi/event.c
148
coreapi/event.c
|
|
@ -35,11 +35,12 @@ const char *linphone_subscription_state_to_string(LinphoneSubscriptionState stat
|
|||
switch(state){
|
||||
case LinphoneSubscriptionNone: return "LinphoneSubscriptionNone";
|
||||
case LinphoneSubscriptionIncomingReceived: return "LinphoneSubscriptionIncomingReceived";
|
||||
case LinphoneSubscriptionOutoingInit: return "LinphoneSubscriptionOutoingInit";
|
||||
case LinphoneSubscriptionOutgoingInit: return "LinphoneSubscriptionOutoingInit";
|
||||
case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending";
|
||||
case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive";
|
||||
case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated";
|
||||
case LinphoneSubscriptionError: return "LinphoneSubscriptionError";
|
||||
case LinphoneSubscriptionExpiring: return "LinphoneSubscriptionExpiring";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -67,8 +68,9 @@ static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscri
|
|||
return lev;
|
||||
}
|
||||
|
||||
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name){
|
||||
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));
|
||||
lev->expires=expires;
|
||||
return lev;
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +107,9 @@ void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState s
|
|||
if (lc->vtable.publish_state_changed){
|
||||
lc->vtable.publish_state_changed(lev->lc,lev,state);
|
||||
}
|
||||
if (state==LinphonePublishCleared){
|
||||
linphone_event_unref(lev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,37 +117,69 @@ LinphonePublishState linphone_event_get_publish_state(const LinphoneEvent *lev){
|
|||
return lev->publish_state;
|
||||
}
|
||||
|
||||
void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason){
|
||||
lev->reason=reason;
|
||||
const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev){
|
||||
return linphone_error_info_from_sal_op(lev->op);
|
||||
}
|
||||
|
||||
LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){
|
||||
return lev->reason;
|
||||
return linphone_error_info_get_reason(linphone_event_get_error_info(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->resource_addr=linphone_address_clone(resource);
|
||||
lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op));
|
||||
return lev;
|
||||
}
|
||||
|
||||
LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
|
||||
LinphoneEvent *lev=linphone_event_new(lc, LinphoneSubscriptionOutgoing, event);
|
||||
SalBody salbody;
|
||||
linphone_configure_op(lc,lev->op,resource,NULL,TRUE);
|
||||
lev->resource_addr=linphone_address_clone(resource);
|
||||
lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op));
|
||||
sal_subscribe(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body));
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionOutoingInit);
|
||||
LinphoneEvent *lev=linphone_core_create_subscribe(lc,resource,event,expires);
|
||||
linphone_event_send_subscribe(lev,body);
|
||||
return lev;
|
||||
}
|
||||
|
||||
|
||||
int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
|
||||
int linphone_event_send_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
|
||||
SalBody salbody;
|
||||
if (lev->subscription_state!=LinphoneSubscriptionActive){
|
||||
ms_error("linphone_event_update_subscribe(): cannot update subscription if subscription wasn't accepted.");
|
||||
return -1;
|
||||
}
|
||||
int err;
|
||||
|
||||
if (lev->dir!=LinphoneSubscriptionOutgoing){
|
||||
ms_error("linphone_event_deny_subscription(): cannot update an incoming subscription.");
|
||||
ms_error("linphone_event_send_subscribe(): cannot send or update something that is not an outgoing subscription.");
|
||||
return -1;
|
||||
}
|
||||
return sal_subscribe(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body));
|
||||
switch (lev->subscription_state){
|
||||
case LinphoneSubscriptionIncomingReceived:
|
||||
case LinphoneSubscriptionTerminated:
|
||||
case LinphoneSubscriptionOutgoingInit:
|
||||
ms_error("linphone_event_send_subscribe(): cannot update subscription while in state [%s]", linphone_subscription_state_to_string(lev->subscription_state));
|
||||
return -1;
|
||||
break;
|
||||
case LinphoneSubscriptionNone:
|
||||
case LinphoneSubscriptionActive:
|
||||
case LinphoneSubscriptionExpiring:
|
||||
case LinphoneSubscriptionError:
|
||||
case LinphoneSubscriptionPending:
|
||||
/*those states are ok*/
|
||||
break;
|
||||
}
|
||||
|
||||
if (lev->send_custom_headers){
|
||||
sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers);
|
||||
lev->send_custom_headers=NULL;
|
||||
}else sal_op_set_sent_custom_header(lev->op,NULL);
|
||||
|
||||
err=sal_subscribe(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body));
|
||||
if (err==0){
|
||||
if (lev->subscription_state==LinphoneSubscriptionNone)
|
||||
linphone_event_set_state(lev,LinphoneSubscriptionOutgoingInit);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int linphone_event_update_subscribe(LinphoneEvent *lev, const LinphoneContent *body){
|
||||
return linphone_event_send_subscribe(lev,body);
|
||||
}
|
||||
|
||||
int linphone_event_accept_subscription(LinphoneEvent *lev){
|
||||
|
|
@ -182,34 +219,55 @@ int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){
|
|||
return sal_notify(lev->op,sal_body_from_content(&salbody,body));
|
||||
}
|
||||
|
||||
LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
|
||||
LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires){
|
||||
LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event,expires);
|
||||
linphone_configure_op(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0));
|
||||
sal_op_set_manual_refresher_mode(lev->op,!lp_config_get_int(lc->config,"sip","refresh_generic_publish",1));
|
||||
return lev;
|
||||
}
|
||||
|
||||
static int _linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body, bool_t notify_err){
|
||||
SalBody salbody;
|
||||
int err;
|
||||
LinphoneEvent *lev=linphone_event_new(lc,LinphoneSubscriptionInvalidDir, event);
|
||||
linphone_configure_op(lc,lev->op,resource,NULL,lp_config_get_int(lc->config,"sip","publish_msg_with_contact",0));
|
||||
sal_op_set_manual_refresher_mode(lev->op,lp_config_get_int(lc->config,"sip","refresh_generic_publish",1));
|
||||
err=sal_publish(lev->op,NULL,NULL,event,expires,sal_body_from_content(&salbody,body));
|
||||
|
||||
if (lev->dir!=LinphoneSubscriptionInvalidDir){
|
||||
ms_error("linphone_event_update_publish(): this is not a PUBLISH event.");
|
||||
return -1;
|
||||
}
|
||||
if (lev->send_custom_headers){
|
||||
sal_op_set_sent_custom_header(lev->op,lev->send_custom_headers);
|
||||
lev->send_custom_headers=NULL;
|
||||
}else sal_op_set_sent_custom_header(lev->op,NULL);
|
||||
err=sal_publish(lev->op,NULL,NULL,lev->name,lev->expires,sal_body_from_content(&salbody,body));
|
||||
if (err==0){
|
||||
linphone_event_set_publish_state(lev,LinphonePublishProgress);
|
||||
}else{
|
||||
}else if (notify_err){
|
||||
linphone_event_set_publish_state(lev,LinphonePublishError);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body){
|
||||
int err;
|
||||
LinphoneEvent *lev=linphone_core_create_publish(lc,resource,event,expires);
|
||||
err=_linphone_event_send_publish(lev,body,FALSE);
|
||||
if (err==-1){
|
||||
linphone_event_unref(lev);
|
||||
lev=NULL;
|
||||
}
|
||||
return lev;
|
||||
}
|
||||
|
||||
int linphone_event_update_publish(LinphoneEvent *lev, const LinphoneContent *body){
|
||||
SalBody salbody;
|
||||
int err;
|
||||
err=sal_publish(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body));
|
||||
if (err==0){
|
||||
linphone_event_set_publish_state(lev,LinphonePublishProgress);
|
||||
}else{
|
||||
linphone_event_set_publish_state(lev,LinphonePublishError);
|
||||
}
|
||||
return err;
|
||||
|
||||
int linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body){
|
||||
return _linphone_event_send_publish(lev,body,TRUE);
|
||||
}
|
||||
|
||||
int linphone_event_update_publish(LinphoneEvent* lev, const LinphoneContent* body ) {
|
||||
return linphone_event_send_publish(lev,body);
|
||||
}
|
||||
|
||||
|
||||
void linphone_event_set_user_data(LinphoneEvent *ev, void *up){
|
||||
ev->userdata=up;
|
||||
}
|
||||
|
|
@ -218,6 +276,16 @@ void *linphone_event_get_user_data(const LinphoneEvent *ev){
|
|||
return ev->userdata;
|
||||
}
|
||||
|
||||
void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const char *value){
|
||||
ev->send_custom_headers=sal_custom_header_append(ev->send_custom_headers, name, value);
|
||||
}
|
||||
|
||||
const char* linphone_event_get_custom_header(LinphoneEvent* ev, const char* name){
|
||||
const SalCustomHeader *ch=sal_op_get_recv_custom_header(ev->op);
|
||||
return sal_custom_header_find(ch,name);
|
||||
}
|
||||
|
||||
|
||||
void linphone_event_terminate(LinphoneEvent *lev){
|
||||
lev->terminating=TRUE;
|
||||
if (lev->dir==LinphoneSubscriptionIncoming){
|
||||
|
|
@ -227,9 +295,10 @@ void linphone_event_terminate(LinphoneEvent *lev){
|
|||
}
|
||||
|
||||
if (lev->publish_state!=LinphonePublishNone){
|
||||
if (lev->publish_state==LinphonePublishOk){
|
||||
if (lev->publish_state==LinphonePublishOk && lev->expires!=-1){
|
||||
sal_publish(lev->op,NULL,NULL,NULL,0,NULL);
|
||||
}
|
||||
}else sal_op_stop_refreshing(lev->op);
|
||||
linphone_event_set_publish_state(lev,LinphonePublishCleared);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +306,6 @@ void linphone_event_terminate(LinphoneEvent *lev){
|
|||
linphone_event_set_state(lev,LinphoneSubscriptionTerminated);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -280,3 +348,7 @@ const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){
|
|||
return lev->resource_addr;
|
||||
}
|
||||
|
||||
LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev){
|
||||
return lev->lc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,14 +52,18 @@ typedef enum _LinphoneSubscriptionDir LinphoneSubscriptionDir;
|
|||
**/
|
||||
enum _LinphoneSubscriptionState{
|
||||
LinphoneSubscriptionNone, /**< Initial state, should not be used.**/
|
||||
LinphoneSubscriptionOutoingInit, /**<An outgoing subcription was created*/
|
||||
LinphoneSubscriptionOutgoingProgress, /**<An outgoing subcription was sent*/
|
||||
LinphoneSubscriptionIncomingReceived, /**<An incoming subcription is received*/
|
||||
LinphoneSubscriptionPending, /**<Subscription is pending, waiting for user approval*/
|
||||
LinphoneSubscriptionActive, /**<Subscription is accepted.*/
|
||||
LinphoneSubscriptionTerminated, /**<Subscription is terminated normally*/
|
||||
LinphoneSubscriptionError /**<Subscription encountered an error, indicated by linphone_event_get_reason()*/
|
||||
LinphoneSubscriptionError, /**<Subscription encountered an error, indicated by linphone_event_get_reason()*/
|
||||
LinphoneSubscriptionExpiring, /**<Subscription is about to expire, only sent if [sip]->refresh_generic_subscribe property is set to 0.*/
|
||||
};
|
||||
/*typo compatibility*/
|
||||
#define LinphoneSubscriptionOutoingInit LinphoneSubscriptionOutgoingInit
|
||||
|
||||
#define LinphoneSubscriptionOutgoingInit LinphoneSubscriptionOutgoingProgress
|
||||
/**
|
||||
* Typedef for subscription state enum.
|
||||
**/
|
||||
|
|
@ -72,7 +76,7 @@ LINPHONE_PUBLIC const char *linphone_subscription_state_to_string(LinphoneSubscr
|
|||
**/
|
||||
enum _LinphonePublishState{
|
||||
LinphonePublishNone, /**< Initial state, do not use**/
|
||||
LinphonePublishProgress, /**<An outgoing subcription was created*/
|
||||
LinphonePublishProgress, /**<An outgoing publish was created and submitted*/
|
||||
LinphonePublishOk, /**<Publish is accepted.*/
|
||||
LinphonePublishError, /**<Publish encoutered an error, linphone_event_get_reason() gives reason code*/
|
||||
LinphonePublishExpiring, /**<Publish is about to expire, only sent if [sip]->refresh_generic_publish property is set to 0.*/
|
||||
|
|
@ -114,7 +118,28 @@ typedef void (*LinphoneCorePublishStateChangedCb)(LinphoneCore *lc, LinphoneEven
|
|||
LINPHONE_PUBLIC LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body);
|
||||
|
||||
/**
|
||||
* Update an outgoing subscription.
|
||||
* Create an outgoing subscription, specifying the destination resource, the event name, and an optional content body.
|
||||
* If accepted, the subscription runs for a finite period, but is automatically renewed if not terminated before.
|
||||
* Unlike linphone_core_subscribe() the subscription isn't sent immediately. It will be send when calling linphone_event_send_subscribe().
|
||||
* @param lc the #LinphoneCore
|
||||
* @param resource the destination resource
|
||||
* @param event the event name
|
||||
* @param expires the whished duration of the subscription
|
||||
* @param body an optional body, may be NULL.
|
||||
* @return a LinphoneEvent holding the context of the created subcription.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires);
|
||||
|
||||
/**
|
||||
* Send a subscription previously created by linphone_core_create_subscribe().
|
||||
* @param ev the LinphoneEvent
|
||||
* @param body optional content to attach with the subscription.
|
||||
* @return 0 if successful, -1 otherwise.
|
||||
**/
|
||||
LINPHONE_PUBLIC int linphone_event_send_subscribe(LinphoneEvent *ev, const LinphoneContent *body);
|
||||
|
||||
/**
|
||||
* Update (refresh) an outgoing subscription.
|
||||
* @param lev a LinphoneEvent
|
||||
* @param body an optional body to include in the subscription update, may be NULL.
|
||||
**/
|
||||
|
|
@ -140,18 +165,38 @@ LINPHONE_PUBLIC int linphone_event_notify(LinphoneEvent *lev, const LinphoneCont
|
|||
|
||||
/**
|
||||
* Publish an event state.
|
||||
* This first create a LinphoneEvent with linphone_core_create_publish() and calls linphone_event_send_publish() to actually send it.
|
||||
* After expiry, the publication is refreshed unless it is terminated before.
|
||||
* @param lc the #LinphoneCore
|
||||
* @param resource the resource uri for the event
|
||||
* @param event the event name
|
||||
* @param expires the lifetime of the publication
|
||||
* @param expires the lifetime of event being published, -1 if no associated duration, in which case it will not be refreshed.
|
||||
* @param body the actual published data
|
||||
* @return the LinphoneEvent holding the context of the publish.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneEvent *linphone_core_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires, const LinphoneContent *body);
|
||||
|
||||
/**
|
||||
* Update a publication.
|
||||
* Create a publish context for an event state.
|
||||
* After being created, the publish must be sent using linphone_event_send_publish().
|
||||
* After expiry, the publication is refreshed unless it is terminated before.
|
||||
* @param lc the #LinphoneCore
|
||||
* @param resource the resource uri for the event
|
||||
* @param event the event name
|
||||
* @param expires the lifetime of event being published, -1 if no associated duration, in which case it will not be refreshed.
|
||||
* @return the LinphoneEvent holding the context of the publish.
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_publish(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires);
|
||||
|
||||
/**
|
||||
* Send a publish created by linphone_core_create_publish().
|
||||
* @param lev the #LinphoneEvent
|
||||
* @param body the new data to be published
|
||||
**/
|
||||
LINPHONE_PUBLIC int linphone_event_send_publish(LinphoneEvent *lev, const LinphoneContent *body);
|
||||
|
||||
/**
|
||||
* Update (refresh) a publish.
|
||||
* @param lev the #LinphoneEvent
|
||||
* @param body the new data to be published
|
||||
**/
|
||||
|
|
@ -163,6 +208,11 @@ LINPHONE_PUBLIC int linphone_event_update_publish(LinphoneEvent *lev, const Linp
|
|||
**/
|
||||
LINPHONE_PUBLIC LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev);
|
||||
|
||||
/**
|
||||
* Get full details about an error occured.
|
||||
**/
|
||||
const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev);
|
||||
|
||||
/**
|
||||
* Get subscription state. If the event object was not created by a subscription mechanism, #LinphoneSubscriptionNone is returned.
|
||||
**/
|
||||
|
|
@ -189,6 +239,22 @@ LINPHONE_PUBLIC void linphone_event_set_user_data(LinphoneEvent *ev, void *up);
|
|||
**/
|
||||
LINPHONE_PUBLIC void *linphone_event_get_user_data(const LinphoneEvent *ev);
|
||||
|
||||
/**
|
||||
* Add a custom header to an outgoing susbscription or publish.
|
||||
* @param ev the LinphoneEvent
|
||||
* @param name header's name
|
||||
* @param value the header's value.
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_event_add_custom_header(LinphoneEvent *ev, const char *name, const char *value);
|
||||
|
||||
/**
|
||||
* Obtain the value of a given header for an incoming subscription.
|
||||
* @param ev the LinphoneEvent
|
||||
* @param name header's name
|
||||
* @return the header's value or NULL if such header doesn't exist.
|
||||
**/
|
||||
LINPHONE_PUBLIC const char *linphone_event_get_custom_header(LinphoneEvent *ev, const char *name);
|
||||
|
||||
/**
|
||||
* Terminate an incoming or outgoing subscription that was previously acccepted, or a previous publication.
|
||||
* This function does not unref the object. The core will unref() if it does not need this object anymore.
|
||||
|
|
@ -229,6 +295,11 @@ LINPHONE_PUBLIC const LinphoneAddress *linphone_event_get_from(const LinphoneEve
|
|||
**/
|
||||
LINPHONE_PUBLIC const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev);
|
||||
|
||||
/**
|
||||
* Returns back pointer to the LinphoneCore that created this LinphoneEvent
|
||||
**/
|
||||
LINPHONE_PUBLIC LinphoneCore *linphone_event_get_core(const LinphoneEvent *lev);
|
||||
|
||||
/**
|
||||
* @}
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -380,6 +380,37 @@ BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){
|
|||
return lf->info;
|
||||
}
|
||||
|
||||
/*
|
||||
* updates the subscriptions.
|
||||
* If only_when_registered is TRUE, subscribe will be sent only if the friend's corresponding proxy config is in registered.
|
||||
* Otherwise if the proxy config goes to unregistered state, the subscription refresh will be suspended.
|
||||
* An optional proxy whose state has changed can be passed to optimize the processing.
|
||||
**/
|
||||
void linphone_friend_update_subscribes(LinphoneFriend *fr, LinphoneProxyConfig *proxy, bool_t only_when_registered){
|
||||
int can_subscribe=1;
|
||||
|
||||
if (only_when_registered && (fr->subscribe || fr->subscribe_active)){
|
||||
LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(fr->lc,fr->uri);
|
||||
if (proxy && proxy!=cfg) return;
|
||||
if (cfg && cfg->state!=LinphoneRegistrationOk){
|
||||
char *tmp=linphone_address_as_string(fr->uri);
|
||||
ms_message("Friend [%s] belongs to proxy config with identity [%s], but this one isn't registered. Subscription is suspended.",
|
||||
tmp,linphone_proxy_config_get_identity(cfg));
|
||||
ms_free(tmp);
|
||||
can_subscribe=0;
|
||||
}
|
||||
}
|
||||
if (can_subscribe && fr->subscribe && fr->subscribe_active==FALSE){
|
||||
ms_message("Sending a new SUBSCRIBE");
|
||||
__linphone_friend_do_subscribe(fr);
|
||||
}else if (can_subscribe && fr->subscribe_active && !fr->subscribe){
|
||||
linphone_friend_unsubscribe(fr);
|
||||
}else if (!can_subscribe && fr->outsub){
|
||||
fr->subscribe_active=FALSE;
|
||||
sal_op_stop_refreshing(fr->outsub);
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
|
||||
LinphonePresenceModel *model;
|
||||
|
||||
|
|
@ -407,12 +438,8 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
|
|||
}
|
||||
fr->inc_subscribe_pending=FALSE;
|
||||
}
|
||||
if (fr->subscribe && fr->subscribe_active==FALSE){
|
||||
ms_message("Sending a new SUBSCRIBE");
|
||||
__linphone_friend_do_subscribe(fr);
|
||||
}else if (fr->subscribe_active && !fr->subscribe){
|
||||
linphone_friend_unsubscribe(fr);
|
||||
}
|
||||
if (fr->lc)
|
||||
linphone_friend_update_subscribes(fr,NULL,linphone_core_should_subscribe_friends_only_when_registered(fr->lc));
|
||||
ms_message("linphone_friend_apply() done.");
|
||||
lc->bl_refresh=TRUE;
|
||||
fr->commit=FALSE;
|
||||
|
|
@ -465,31 +492,22 @@ void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){
|
|||
}
|
||||
}
|
||||
|
||||
void linphone_core_send_initial_subscribes(LinphoneCore *lc){
|
||||
void linphone_core_update_friends_subscriptions(LinphoneCore *lc, LinphoneProxyConfig *cfg, bool_t only_when_registered){
|
||||
const MSList *elem;
|
||||
if (lc->initial_subscribes_sent) return;
|
||||
lc->initial_subscribes_sent=TRUE; /*set to true and see if looping on friends will change this status*/
|
||||
for(elem=lc->friends;elem!=NULL;elem=elem->next){
|
||||
LinphoneFriend *f=(LinphoneFriend*)elem->data;
|
||||
LinphoneProxyConfig* cfg;
|
||||
if (f->subscribe && !f->initial_subscribes_sent) {
|
||||
lc->initial_subscribes_sent=FALSE; /*at least 1 was not sent */
|
||||
if ((cfg=linphone_core_lookup_known_proxy(f->lc,linphone_friend_get_address(f)))) {
|
||||
/*check if already registered*/
|
||||
if (linphone_proxy_config_get_state(cfg) != LinphoneRegistrationOk)
|
||||
continue; /*skip this friend because not registered yet*/
|
||||
else {
|
||||
char* lf_string = linphone_address_as_string(linphone_friend_get_address(f));
|
||||
ms_message("Identity [%s] registered, we can now subscribe to [%s]",linphone_proxy_config_get_identity(cfg),lf_string);
|
||||
ms_free(lf_string);
|
||||
}
|
||||
}
|
||||
linphone_friend_apply(f,lc);
|
||||
f->initial_subscribes_sent=TRUE;
|
||||
}
|
||||
|
||||
linphone_friend_update_subscribes(f,cfg,only_when_registered);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void linphone_core_send_initial_subscribes(LinphoneCore *lc){
|
||||
if (lc->initial_subscribes_sent) return;
|
||||
lc->initial_subscribes_sent=TRUE;
|
||||
linphone_core_update_friends_subscriptions(lc,NULL,linphone_core_should_subscribe_friends_only_when_registered(lc));
|
||||
}
|
||||
|
||||
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc){
|
||||
|
|
@ -656,3 +674,7 @@ void linphone_core_write_friends_config(LinphoneCore* lc)
|
|||
linphone_friend_write_to_config_file(lc->config,NULL,i); /* set the end */
|
||||
}
|
||||
|
||||
LinphoneCore *linphone_friend_get_core(const LinphoneFriend *fr){
|
||||
return fr->lc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ LINPHONE_TUTOS=$(helloworld_SOURCES)
|
|||
|
||||
helloworld_LDADD=$(top_builddir)/coreapi/liblinphone.la \
|
||||
$(MEDIASTREAMER_LIBS) \
|
||||
$(ORTP_LIBS)
|
||||
$(ORTP_LIBS) \
|
||||
$(BELLESIP_LIBS)
|
||||
|
||||
registration_SOURCES=registration.c
|
||||
LINPHONE_TUTOS+=$(registration_SOURCES)
|
||||
|
|
@ -85,7 +86,8 @@ AM_CFLAGS=\
|
|||
-DLOG_DOMAIN=\"LinphoneCore\" \
|
||||
$(IPV6_CFLAGS) \
|
||||
-DORTP_INET6 \
|
||||
$(VIDEO_CFLAGS)
|
||||
$(VIDEO_CFLAGS) \
|
||||
$(BELLESIP_CFLAGS)
|
||||
|
||||
|
||||
tutodir=$(datadir)/tutorials/linphone
|
||||
|
|
|
|||
|
|
@ -20,24 +20,25 @@ package org.linphone.core.tutorials;
|
|||
|
||||
import org.linphone.core.LinphoneAddress;
|
||||
import org.linphone.core.LinphoneCall;
|
||||
import org.linphone.core.LinphoneCall.State;
|
||||
import org.linphone.core.LinphoneCallStats;
|
||||
import org.linphone.core.LinphoneChatMessage;
|
||||
import org.linphone.core.LinphoneChatRoom;
|
||||
import org.linphone.core.LinphoneContent;
|
||||
import org.linphone.core.LinphoneCore;
|
||||
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
|
||||
import org.linphone.core.LinphoneCore.GlobalState;
|
||||
import org.linphone.core.LinphoneCore.RegistrationState;
|
||||
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
|
||||
import org.linphone.core.LinphoneCoreException;
|
||||
import org.linphone.core.LinphoneCoreFactory;
|
||||
import org.linphone.core.LinphoneCoreListener;
|
||||
import org.linphone.core.LinphoneEvent;
|
||||
import org.linphone.core.LinphoneFriend;
|
||||
import org.linphone.core.LinphoneFriend.SubscribePolicy;
|
||||
import org.linphone.core.LinphoneInfoMessage;
|
||||
import org.linphone.core.LinphoneProxyConfig;
|
||||
import org.linphone.core.OnlineStatus;
|
||||
import org.linphone.core.LinphoneCall.State;
|
||||
import org.linphone.core.LinphoneCore.GlobalState;
|
||||
import org.linphone.core.LinphoneCore.RegistrationState;
|
||||
import org.linphone.core.LinphoneFriend.SubscribePolicy;
|
||||
import org.linphone.core.PublishState;
|
||||
import org.linphone.core.SubscriptionState;
|
||||
|
||||
|
|
@ -96,7 +97,6 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
|
|||
}
|
||||
public void show(LinphoneCore lc) {}
|
||||
public void byeReceived(LinphoneCore lc, String from) {}
|
||||
public void authInfoRequested(LinphoneCore lc, String realm, String username) {}
|
||||
public void displayStatus(LinphoneCore lc, String message) {}
|
||||
public void displayMessage(LinphoneCore lc, String message) {}
|
||||
public void displayWarning(LinphoneCore lc, String message) {}
|
||||
|
|
@ -140,7 +140,7 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
|
|||
|
||||
// First instantiate the core Linphone object given only a listener.
|
||||
// The listener will react to events in Linphone core.
|
||||
LinphoneCore lc = lcFactory.createLinphoneCore(this);
|
||||
LinphoneCore lc = lcFactory.createLinphoneCore(this, null);
|
||||
|
||||
|
||||
try {
|
||||
|
|
@ -280,5 +280,25 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configuringStatus(LinphoneCore lc,
|
||||
RemoteProvisioningState state, String message) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authInfoRequested(LinphoneCore lc, String realm,
|
||||
String username, String Domain) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.linphone.core.LinphoneCore;
|
|||
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
|
||||
import org.linphone.core.LinphoneCore.GlobalState;
|
||||
import org.linphone.core.LinphoneCore.RegistrationState;
|
||||
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
|
||||
import org.linphone.core.LinphoneCoreException;
|
||||
import org.linphone.core.LinphoneCoreFactory;
|
||||
import org.linphone.core.LinphoneCoreListener;
|
||||
|
|
@ -72,7 +73,7 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa
|
|||
|
||||
public void show(LinphoneCore lc) {}
|
||||
public void byeReceived(LinphoneCore lc, String from) {}
|
||||
public void authInfoRequested(LinphoneCore lc, String realm, String username) {}
|
||||
public void authInfoRequested(LinphoneCore lc, String realm, String username, String domain) {}
|
||||
public void displayStatus(LinphoneCore lc, String message) {}
|
||||
public void displayMessage(LinphoneCore lc, String message) {}
|
||||
public void displayWarning(LinphoneCore lc, String message) {}
|
||||
|
|
@ -116,7 +117,7 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa
|
|||
|
||||
// First instantiate the core Linphone object given only a listener.
|
||||
// The listener will react to events in Linphone core.
|
||||
LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this);
|
||||
LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this, null);
|
||||
|
||||
try {
|
||||
// Next step is to create a chat room
|
||||
|
|
@ -202,5 +203,20 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) {
|
||||
if (cr.isRemoteComposing())
|
||||
write("Remote is writing a message");
|
||||
else
|
||||
write("Remote has stop writing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configuringStatus(LinphoneCore lc,
|
||||
RemoteProvisioningState state, String message) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.linphone.core.LinphoneChatRoom;
|
|||
import org.linphone.core.LinphoneContent;
|
||||
import org.linphone.core.LinphoneCore;
|
||||
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
|
||||
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
|
||||
import org.linphone.core.LinphoneCoreException;
|
||||
import org.linphone.core.LinphoneCoreFactory;
|
||||
import org.linphone.core.LinphoneCoreListener;
|
||||
|
|
@ -66,7 +67,7 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
|
|||
|
||||
public void show(LinphoneCore lc) {}
|
||||
public void byeReceived(LinphoneCore lc, String from) {}
|
||||
public void authInfoRequested(LinphoneCore lc, String realm, String username) {}
|
||||
public void authInfoRequested(LinphoneCore lc, String realm, String username, String domain) {}
|
||||
public void displayStatus(LinphoneCore lc, String message) {}
|
||||
public void displayMessage(LinphoneCore lc, String message) {}
|
||||
public void displayWarning(LinphoneCore lc, String message) {}
|
||||
|
|
@ -113,7 +114,7 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
|
|||
|
||||
// First instantiate the core Linphone object given only a listener.
|
||||
// The listener will react to events in Linphone core.
|
||||
LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this);
|
||||
LinphoneCore lc = LinphoneCoreFactory.instance().createLinphoneCore(this, null);
|
||||
|
||||
|
||||
|
||||
|
|
@ -206,5 +207,18 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configuringStatus(LinphoneCore lc,
|
||||
RemoteProvisioningState state, String message) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.linphone.core.LinphoneChatRoom;
|
|||
import org.linphone.core.LinphoneContent;
|
||||
import org.linphone.core.LinphoneCore;
|
||||
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
|
||||
import org.linphone.core.LinphoneCore.RemoteProvisioningState;
|
||||
import org.linphone.core.LinphoneCoreException;
|
||||
import org.linphone.core.LinphoneCoreFactory;
|
||||
import org.linphone.core.LinphoneCoreListener;
|
||||
|
|
@ -77,7 +78,7 @@ public class TutorialRegistration implements LinphoneCoreListener {
|
|||
|
||||
public void show(LinphoneCore lc) {}
|
||||
public void byeReceived(LinphoneCore lc, String from) {}
|
||||
public void authInfoRequested(LinphoneCore lc, String realm, String username) {}
|
||||
public void authInfoRequested(LinphoneCore lc, String realm, String username, String domain) {}
|
||||
public void displayStatus(LinphoneCore lc, String message) {}
|
||||
public void displayMessage(LinphoneCore lc, String message) {}
|
||||
public void displayWarning(LinphoneCore lc, String message) {}
|
||||
|
|
@ -118,7 +119,7 @@ public class TutorialRegistration implements LinphoneCoreListener {
|
|||
|
||||
// First instantiate the core Linphone object given only a listener.
|
||||
// The listener will react to events in Linphone core.
|
||||
LinphoneCore lc = lcFactory.createLinphoneCore(this);
|
||||
LinphoneCore lc = lcFactory.createLinphoneCore(this, null);
|
||||
|
||||
|
||||
try {
|
||||
|
|
@ -237,6 +238,19 @@ public class TutorialRegistration implements LinphoneCoreListener {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isComposingReceived(LinphoneCore lc, LinphoneChatRoom cr) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configuringStatus(LinphoneCore lc,
|
||||
RemoteProvisioningState state, String message) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
826
coreapi/ldap/ldapprovider.c
Normal file
826
coreapi/ldap/ldapprovider.c
Normal file
|
|
@ -0,0 +1,826 @@
|
|||
/*
|
||||
* 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 Library 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 "ldapprovider.h"
|
||||
#include "private.h"
|
||||
#include "lpconfig.h"
|
||||
#include "contact_providers_priv.h"
|
||||
#include "mediastreamer2/mscommon.h"
|
||||
#include <belle-sip/dict.h>
|
||||
|
||||
#ifdef BUILD_LDAP
|
||||
#include <ldap.h>
|
||||
#include <sasl/sasl.h>
|
||||
|
||||
|
||||
#define MAX_RUNNING_REQUESTS 10
|
||||
#define FILTER_MAX_SIZE 512
|
||||
|
||||
struct LDAPFriendData {
|
||||
char* name;
|
||||
char* sip;
|
||||
};
|
||||
|
||||
struct _LinphoneLDAPContactProvider
|
||||
{
|
||||
LinphoneContactProvider base;
|
||||
LinphoneDictionary* config;
|
||||
|
||||
LDAP* ld;
|
||||
MSList* requests;
|
||||
unsigned int req_count;
|
||||
|
||||
// bind transaction
|
||||
bool_t connected;
|
||||
ms_thread_t bind_thread;
|
||||
|
||||
// config
|
||||
int use_tls;
|
||||
const char* auth_method;
|
||||
const char* username;
|
||||
const char* password;
|
||||
const char* server;
|
||||
const char* bind_dn;
|
||||
|
||||
const char* sasl_authname;
|
||||
const char* sasl_realm;
|
||||
|
||||
const char* base_object;
|
||||
const char* sip_attr;
|
||||
const char* name_attr;
|
||||
const char* filter;
|
||||
|
||||
char** attributes;
|
||||
|
||||
int timeout;
|
||||
int deref_aliases;
|
||||
int max_results;
|
||||
|
||||
};
|
||||
|
||||
struct _LinphoneLDAPContactSearch
|
||||
{
|
||||
LinphoneContactSearch base;
|
||||
LDAP* ld;
|
||||
int msgid;
|
||||
char* filter;
|
||||
bool_t complete;
|
||||
MSList* found_entries;
|
||||
unsigned int found_count;
|
||||
};
|
||||
|
||||
|
||||
/* *************************
|
||||
* LinphoneLDAPContactSearch
|
||||
* *************************/
|
||||
|
||||
LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* cp, const char* predicate, ContactSearchCallback cb, void* cb_data)
|
||||
{
|
||||
LinphoneLDAPContactSearch* search = belle_sip_object_new(LinphoneLDAPContactSearch);
|
||||
LinphoneContactSearch* base = LINPHONE_CONTACT_SEARCH(search);
|
||||
|
||||
linphone_contact_search_init(base, predicate, cb, cb_data);
|
||||
|
||||
search->ld = cp->ld;
|
||||
|
||||
search->filter = ms_malloc(FILTER_MAX_SIZE);
|
||||
snprintf(search->filter, FILTER_MAX_SIZE-1, cp->filter, predicate);
|
||||
search->filter[FILTER_MAX_SIZE-1] = 0;
|
||||
|
||||
return search;
|
||||
}
|
||||
|
||||
void linphone_ldap_contact_search_destroy_friend( void* entry )
|
||||
{
|
||||
linphone_friend_destroy((LinphoneFriend*)entry);
|
||||
}
|
||||
|
||||
unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj)
|
||||
{
|
||||
return obj->found_count;
|
||||
}
|
||||
|
||||
static void linphone_ldap_contact_search_destroy( LinphoneLDAPContactSearch* obj )
|
||||
{
|
||||
//ms_message("~LinphoneLDAPContactSearch(%p)", obj);
|
||||
ms_list_for_each(obj->found_entries, linphone_ldap_contact_search_destroy_friend);
|
||||
obj->found_entries = ms_list_free(obj->found_entries);
|
||||
if( obj->filter ) ms_free(obj->filter);
|
||||
}
|
||||
|
||||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactSearch);
|
||||
BELLE_SIP_INSTANCIATE_VPTR(LinphoneLDAPContactSearch,LinphoneContactSearch,
|
||||
(belle_sip_object_destroy_t)linphone_ldap_contact_search_destroy,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE
|
||||
);
|
||||
|
||||
|
||||
/* ***************************
|
||||
* LinphoneLDAPContactProvider
|
||||
* ***************************/
|
||||
|
||||
static inline LinphoneLDAPContactSearch* linphone_ldap_contact_provider_request_search( LinphoneLDAPContactProvider* obj, int msgid );
|
||||
static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req);
|
||||
static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj );
|
||||
static bool_t linphone_ldap_contact_provider_iterate(void *data);
|
||||
static int linphone_ldap_contact_provider_bind_interact(LDAP *ld, unsigned flags, void *defaults, void *sasl_interact);
|
||||
static int linphone_ldap_contact_provider_perform_search( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req);
|
||||
|
||||
static void linphone_ldap_contact_provider_destroy_request_cb(void *req)
|
||||
{
|
||||
belle_sip_object_unref(req);
|
||||
}
|
||||
|
||||
static void linphone_ldap_contact_provider_destroy( LinphoneLDAPContactProvider* obj )
|
||||
{
|
||||
//ms_message("linphone_ldap_contact_provider_destroy");
|
||||
linphone_core_remove_iterate_hook(LINPHONE_CONTACT_PROVIDER(obj)->lc, linphone_ldap_contact_provider_iterate,obj);
|
||||
|
||||
// clean pending requests
|
||||
ms_list_for_each(obj->requests, linphone_ldap_contact_provider_destroy_request_cb);
|
||||
|
||||
if (obj->ld) ldap_unbind_ext(obj->ld, NULL, NULL);
|
||||
obj->ld = NULL;
|
||||
|
||||
if( obj->config ) linphone_dictionary_unref(obj->config);
|
||||
|
||||
linphone_ldap_contact_provider_conf_destroy(obj);
|
||||
}
|
||||
|
||||
static int linphone_ldap_contact_provider_complete_contact( LinphoneLDAPContactProvider* obj, struct LDAPFriendData* lf, const char* attr_name, const char* attr_value)
|
||||
{
|
||||
if( strcmp(attr_name, obj->name_attr ) == 0 ){
|
||||
lf->name = ms_strdup(attr_value);
|
||||
} else if( strcmp(attr_name, obj->sip_attr) == 0 ) {
|
||||
lf->sip = ms_strdup(attr_value);
|
||||
}
|
||||
|
||||
// return 1 if the structure has enough data to create a linphone friend
|
||||
if( lf->name && lf->sip )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void linphone_ldap_contact_provider_handle_search_result( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req, LDAPMessage* message )
|
||||
{
|
||||
int msgtype = ldap_msgtype(message);
|
||||
|
||||
switch(msgtype){
|
||||
|
||||
case LDAP_RES_SEARCH_ENTRY:
|
||||
case LDAP_RES_EXTENDED:
|
||||
{
|
||||
LDAPMessage *entry = ldap_first_entry(obj->ld, message);
|
||||
LinphoneCore* lc = LINPHONE_CONTACT_PROVIDER(obj)->lc;
|
||||
|
||||
while( entry != NULL ){
|
||||
|
||||
struct LDAPFriendData ldap_data = {0};
|
||||
bool_t contact_complete = FALSE;
|
||||
BerElement* ber = NULL;
|
||||
char* attr = ldap_first_attribute(obj->ld, entry, &ber);
|
||||
|
||||
while( attr ){
|
||||
struct berval** values = ldap_get_values_len(obj->ld, entry, attr);
|
||||
struct berval** it = values;
|
||||
|
||||
while( values && *it && (*it)->bv_val && (*it)->bv_len )
|
||||
{
|
||||
contact_complete = linphone_ldap_contact_provider_complete_contact(obj, &ldap_data, attr, (*it)->bv_val);
|
||||
if( contact_complete ) break;
|
||||
|
||||
it++;
|
||||
}
|
||||
|
||||
if( values ) ldap_value_free_len(values);
|
||||
ldap_memfree(attr);
|
||||
|
||||
if( contact_complete ) break;
|
||||
|
||||
attr = ldap_next_attribute(obj->ld, entry, ber);
|
||||
}
|
||||
|
||||
if( contact_complete ) {
|
||||
LinphoneAddress* la = linphone_core_interpret_url(lc, ldap_data.sip);
|
||||
if( la ){
|
||||
LinphoneFriend* lf = linphone_core_create_friend(lc);
|
||||
linphone_friend_set_address(lf, la);
|
||||
linphone_friend_set_name(lf, ldap_data.name);
|
||||
req->found_entries = ms_list_append(req->found_entries, lf);
|
||||
req->found_count++;
|
||||
//ms_message("Added friend %s / %s", ldap_data.name, ldap_data.sip);
|
||||
ms_free(ldap_data.sip);
|
||||
ms_free(ldap_data.name);
|
||||
linphone_address_destroy(la);
|
||||
}
|
||||
}
|
||||
|
||||
if( ber ) ber_free(ber, 0);
|
||||
|
||||
entry = ldap_next_entry(obj->ld, entry);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LDAP_RES_SEARCH_RESULT:
|
||||
{
|
||||
// this one is received when a request is finished
|
||||
req->complete = TRUE;
|
||||
linphone_contact_search_invoke_cb(LINPHONE_CONTACT_SEARCH(req), req->found_entries);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: ms_message("[LDAP] Unhandled message type %x", msgtype); break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool_t linphone_ldap_contact_provider_iterate(void *data)
|
||||
{
|
||||
LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(data);
|
||||
if( obj->ld && obj->connected && (obj->req_count > 0) ){
|
||||
|
||||
// never block
|
||||
struct timeval timeout = {0,0};
|
||||
LDAPMessage* results = NULL;
|
||||
|
||||
int ret = ldap_result(obj->ld, LDAP_RES_ANY, LDAP_MSG_ONE, &timeout, &results);
|
||||
|
||||
switch( ret ){
|
||||
case -1:
|
||||
{
|
||||
ms_warning("Error in ldap_result : returned -1 (req_count %d): %s", obj->req_count, ldap_err2string(errno));
|
||||
break;
|
||||
}
|
||||
case 0: break; // nothing to do
|
||||
|
||||
case LDAP_RES_BIND:
|
||||
{
|
||||
ms_error("iterate: unexpected LDAP_RES_BIND");
|
||||
break;
|
||||
}
|
||||
case LDAP_RES_EXTENDED:
|
||||
case LDAP_RES_SEARCH_ENTRY:
|
||||
case LDAP_RES_SEARCH_REFERENCE:
|
||||
case LDAP_RES_INTERMEDIATE:
|
||||
case LDAP_RES_SEARCH_RESULT:
|
||||
{
|
||||
LDAPMessage* message = ldap_first_message(obj->ld, results);
|
||||
LinphoneLDAPContactSearch* req = linphone_ldap_contact_provider_request_search(obj, ldap_msgid(message));
|
||||
while( message != NULL ){
|
||||
linphone_ldap_contact_provider_handle_search_result(obj, req, message );
|
||||
message = ldap_next_message(obj->ld, message);
|
||||
}
|
||||
if( req && ret == LDAP_RES_SEARCH_RESULT)
|
||||
linphone_ldap_contact_provider_cancel_search(
|
||||
LINPHONE_CONTACT_PROVIDER(obj),
|
||||
LINPHONE_CONTACT_SEARCH(req));
|
||||
break;
|
||||
}
|
||||
case LDAP_RES_MODIFY:
|
||||
case LDAP_RES_ADD:
|
||||
case LDAP_RES_DELETE:
|
||||
case LDAP_RES_MODDN:
|
||||
case LDAP_RES_COMPARE:
|
||||
default:
|
||||
ms_message("Unhandled LDAP result %x", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
if( results )
|
||||
ldap_msgfree(results);
|
||||
}
|
||||
|
||||
if( obj->ld && obj->connected ){
|
||||
// check for pending searches
|
||||
unsigned int i;
|
||||
|
||||
for( i=0; i<obj->req_count; i++){
|
||||
LinphoneLDAPContactSearch* search = (LinphoneLDAPContactSearch*)ms_list_nth_data( obj->requests, i );
|
||||
if( search && search->msgid == 0){
|
||||
int ret;
|
||||
ms_message("Found pending search %p (for %s), launching...", search, search->filter);
|
||||
ret = linphone_ldap_contact_provider_perform_search(obj, search);
|
||||
if( ret != LDAP_SUCCESS ){
|
||||
linphone_ldap_contact_provider_cancel_search(
|
||||
LINPHONE_CONTACT_PROVIDER(obj),
|
||||
LINPHONE_CONTACT_SEARCH(search));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void linphone_ldap_contact_provider_conf_destroy(LinphoneLDAPContactProvider* obj )
|
||||
{
|
||||
if(obj->attributes){
|
||||
int i=0;
|
||||
for( ; obj->attributes[i]; i++){
|
||||
ms_free(obj->attributes[i]);
|
||||
}
|
||||
ms_free(obj->attributes);
|
||||
}
|
||||
}
|
||||
|
||||
static char* required_config_keys[] = {
|
||||
// connection
|
||||
"server",
|
||||
"use_tls",
|
||||
"auth_method",
|
||||
"username",
|
||||
"password",
|
||||
"bind_dn",
|
||||
"sasl_authname",
|
||||
"sasl_realm",
|
||||
|
||||
// search
|
||||
"base_object",
|
||||
"filter",
|
||||
"name_attribute",
|
||||
"sip_attribute",
|
||||
"attributes",
|
||||
|
||||
// misc
|
||||
"timeout",
|
||||
"max_results",
|
||||
"deref_aliases",
|
||||
NULL
|
||||
};
|
||||
|
||||
static bool_t linphone_ldap_contact_provider_valid_config(const LinphoneDictionary* dict)
|
||||
{
|
||||
char** config_name = required_config_keys;
|
||||
|
||||
bool_t valid = TRUE;
|
||||
bool_t has_key;
|
||||
|
||||
while(*config_name ){
|
||||
has_key = linphone_dictionary_haskey(dict, *config_name);
|
||||
if( !has_key ) ms_error("Missing LDAP config value for '%s'", *config_name);
|
||||
valid &= has_key;
|
||||
config_name++;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
static void linphone_ldap_contact_provider_loadconfig(LinphoneLDAPContactProvider* obj, const LinphoneDictionary* dict)
|
||||
{
|
||||
char* attributes_list, *saveptr, *attr;
|
||||
unsigned int attr_count = 0, attr_idx = 0, i;
|
||||
|
||||
if( !linphone_ldap_contact_provider_valid_config(dict) ) return;
|
||||
|
||||
// free any pre-existing attributes values
|
||||
linphone_ldap_contact_provider_conf_destroy(obj);
|
||||
if( obj->config ) linphone_dictionary_unref(obj->config);
|
||||
|
||||
// clone new config into the dictionary
|
||||
obj->config = linphone_dictionary_ref(linphone_dictionary_clone(dict));
|
||||
|
||||
#if 0 // until sasl auth is set up, force anonymous auth.
|
||||
linphone_dictionary_set_string(obj->config, "auth_method", "ANONYMOUS");
|
||||
#endif
|
||||
|
||||
obj->use_tls = linphone_dictionary_get_int(obj->config, "use_tls", 0);
|
||||
obj->timeout = linphone_dictionary_get_int(obj->config, "timeout", 10);
|
||||
obj->deref_aliases = linphone_dictionary_get_int(obj->config, "deref_aliases", 0);
|
||||
obj->max_results = linphone_dictionary_get_int(obj->config, "max_results", 50);
|
||||
obj->auth_method = linphone_dictionary_get_string(obj->config, "auth_method", "ANONYMOUS");
|
||||
obj->username = linphone_dictionary_get_string(obj->config, "username", "");
|
||||
obj->password = linphone_dictionary_get_string(obj->config, "password", "");
|
||||
obj->bind_dn = linphone_dictionary_get_string(obj->config, "bind_dn", "");
|
||||
obj->base_object = linphone_dictionary_get_string(obj->config, "base_object", "dc=example,dc=com");
|
||||
obj->server = linphone_dictionary_get_string(obj->config, "server", "ldap://localhost");
|
||||
obj->filter = linphone_dictionary_get_string(obj->config, "filter", "uid=*%s*");
|
||||
obj->name_attr = linphone_dictionary_get_string(obj->config, "name_attribute", "givenName");
|
||||
obj->sip_attr = linphone_dictionary_get_string(obj->config, "sip_attribute", "mobile");
|
||||
obj->sasl_authname = linphone_dictionary_get_string(obj->config, "sasl_authname", "");
|
||||
obj->sasl_realm = linphone_dictionary_get_string(obj->config, "sasl_realm", "");
|
||||
|
||||
/*
|
||||
* parse the attributes list
|
||||
*/
|
||||
attributes_list = ms_strdup(
|
||||
linphone_dictionary_get_string(obj->config,
|
||||
"attributes",
|
||||
"telephoneNumber,givenName,sn,mobile,homePhone")
|
||||
);
|
||||
|
||||
// count attributes:
|
||||
for( i=0; attributes_list[i]; i++) {
|
||||
if( attributes_list[i] == ',') attr_count++;
|
||||
}
|
||||
|
||||
// 1 more for the first attr without ',', the other for the null-finished list
|
||||
obj->attributes = ms_malloc0((attr_count+2) * sizeof(char*));
|
||||
|
||||
attr = strtok_r( attributes_list, ",", &saveptr );
|
||||
while( attr != NULL ){
|
||||
obj->attributes[attr_idx] = ms_strdup(attr);
|
||||
attr_idx++;
|
||||
attr = strtok_r(NULL, ",", &saveptr);
|
||||
}
|
||||
if( attr_idx != attr_count+1) ms_error("Invalid attribute number!!! %d expected, got %d", attr_count+1, attr_idx);
|
||||
|
||||
ms_free(attributes_list);
|
||||
}
|
||||
|
||||
static int linphone_ldap_contact_provider_bind_interact(LDAP *ld,
|
||||
unsigned flags,
|
||||
void *defaults,
|
||||
void *sasl_interact)
|
||||
{
|
||||
sasl_interact_t *interact = (sasl_interact_t*)sasl_interact;
|
||||
LinphoneLDAPContactProvider* obj = LINPHONE_LDAP_CONTACT_PROVIDER(defaults);
|
||||
ms_message("bind_interact called: ld %p, flags %x, default %p, interact %p",
|
||||
ld, flags, defaults, sasl_interact);
|
||||
|
||||
if( ld == NULL ) return LDAP_PARAM_ERROR;
|
||||
|
||||
while( interact->id != SASL_CB_LIST_END ) {
|
||||
|
||||
const char *dflt = interact->defresult;
|
||||
|
||||
switch( interact->id ) {
|
||||
case SASL_CB_GETREALM:
|
||||
ms_message("* SASL_CB_GETREALM -> %s", obj->sasl_realm);
|
||||
dflt = obj->sasl_realm;
|
||||
break;
|
||||
case SASL_CB_AUTHNAME:
|
||||
ms_message("* SASL_CB_AUTHNAME -> %s", obj->sasl_authname);
|
||||
dflt = obj->sasl_authname;
|
||||
break;
|
||||
case SASL_CB_USER:
|
||||
ms_message("* SASL_CB_USER -> %s", obj->username);
|
||||
dflt = obj->username;
|
||||
break;
|
||||
case SASL_CB_PASS:
|
||||
ms_message("* SASL_CB_PASS (hidden)");
|
||||
dflt = obj->password;
|
||||
break;
|
||||
default:
|
||||
ms_message("SASL interact asked for unknown id %lx\n",interact->id);
|
||||
}
|
||||
interact->result = (dflt && *dflt) ? dflt : (const char*)"";
|
||||
interact->len = strlen( (const char*)interact->result );
|
||||
|
||||
interact++;
|
||||
}
|
||||
return LDAP_SUCCESS;
|
||||
}
|
||||
|
||||
static void* ldap_bind_thread_func( void*arg)
|
||||
{
|
||||
LinphoneLDAPContactProvider* obj = linphone_ldap_contact_provider_ref(arg);
|
||||
const char* auth_mechanism = obj->auth_method;
|
||||
int ret;
|
||||
|
||||
if( (strcmp(auth_mechanism, "ANONYMOUS") == 0) || (strcmp(auth_mechanism, "SIMPLE") == 0) )
|
||||
{
|
||||
struct berval passwd = { strlen(obj->password), ms_strdup(obj->password)};
|
||||
auth_mechanism = LDAP_SASL_SIMPLE;
|
||||
ret = ldap_sasl_bind_s(obj->ld,
|
||||
obj->bind_dn,
|
||||
auth_mechanism,
|
||||
&passwd,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
ms_free(passwd.bv_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
ms_message("LDAP interactive bind");
|
||||
ret = ldap_sasl_interactive_bind_s(obj->ld,
|
||||
obj->bind_dn,
|
||||
auth_mechanism,
|
||||
NULL,NULL,
|
||||
LDAP_SASL_QUIET,
|
||||
linphone_ldap_contact_provider_bind_interact,
|
||||
obj);
|
||||
}
|
||||
|
||||
if( ret == LDAP_SUCCESS ) {
|
||||
ms_message("LDAP bind OK");
|
||||
obj->connected = 1;
|
||||
} else {
|
||||
int err;
|
||||
ldap_get_option(obj->ld, LDAP_OPT_RESULT_CODE, &err);
|
||||
ms_error("ldap_sasl_bind error returned %x, err %x (%s), auth_method: %s",
|
||||
ret, err, ldap_err2string(err), auth_mechanism );
|
||||
}
|
||||
|
||||
obj->bind_thread = 0;
|
||||
linphone_ldap_contact_provider_unref(obj);
|
||||
return (void*)0;
|
||||
}
|
||||
|
||||
static int linphone_ldap_contact_provider_bind( LinphoneLDAPContactProvider* obj )
|
||||
{
|
||||
// perform the bind in an alternate thread, so that we don't stall the main loop
|
||||
ms_thread_create(&obj->bind_thread, NULL, ldap_bind_thread_func, obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj)
|
||||
{
|
||||
return obj->max_results;
|
||||
}
|
||||
|
||||
static void linphone_ldap_contact_provider_config_dump_cb(const char*key, void* value, void* userdata)
|
||||
{
|
||||
ms_message("- %s -> %s", key, (const char* )value);
|
||||
}
|
||||
|
||||
LinphoneLDAPContactProvider*linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config)
|
||||
{
|
||||
LinphoneLDAPContactProvider* obj = belle_sip_object_new(LinphoneLDAPContactProvider);
|
||||
int proto_version = LDAP_VERSION3;
|
||||
|
||||
linphone_contact_provider_init((LinphoneContactProvider*)obj, lc);
|
||||
|
||||
ms_message( "Constructed Contact provider '%s'", BELLE_SIP_OBJECT_VPTR(obj,LinphoneContactProvider)->name);
|
||||
|
||||
if( !linphone_ldap_contact_provider_valid_config(config) ) {
|
||||
ms_error( "Invalid configuration for LDAP, aborting creation");
|
||||
belle_sip_object_unref(obj);
|
||||
obj = NULL;
|
||||
} else {
|
||||
linphone_dictionary_foreach( config, linphone_ldap_contact_provider_config_dump_cb, 0 );
|
||||
linphone_ldap_contact_provider_loadconfig(obj, config);
|
||||
|
||||
int ret = ldap_initialize(&(obj->ld),obj->server);
|
||||
|
||||
if( ret != LDAP_SUCCESS ){
|
||||
ms_error( "Problem initializing ldap on url '%s': %s", obj->server, ldap_err2string(ret));
|
||||
belle_sip_object_unref(obj);
|
||||
obj = NULL;
|
||||
} else if( (ret = ldap_set_option(obj->ld, LDAP_OPT_PROTOCOL_VERSION, &proto_version)) != LDAP_SUCCESS ){
|
||||
ms_error( "Problem setting protocol version %d: %s", proto_version, ldap_err2string(ret));
|
||||
belle_sip_object_unref(obj);
|
||||
obj = NULL;
|
||||
} else {
|
||||
// prevents blocking calls to bind() when the server is invalid, but this is not working for now..
|
||||
// see bug https://bugzilla.mozilla.org/show_bug.cgi?id=79509
|
||||
//ldap_set_option( obj->ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON);
|
||||
|
||||
// register our hook into iterate so that LDAP can do its magic asynchronously.
|
||||
linphone_core_add_iterate_hook(lc, linphone_ldap_contact_provider_iterate, obj);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search an LDAP request in the list of current LDAP requests to serve, only taking
|
||||
* the msgid as a key to search.
|
||||
*/
|
||||
static int linphone_ldap_request_entry_compare_weak(const void*a, const void* b)
|
||||
{
|
||||
const LinphoneLDAPContactSearch* ra = (const LinphoneLDAPContactSearch*)a;
|
||||
const LinphoneLDAPContactSearch* rb = (const LinphoneLDAPContactSearch*)b;
|
||||
return !(ra->msgid == rb->msgid); // 0 if equal
|
||||
}
|
||||
|
||||
/**
|
||||
* Search an LDAP request in the list of current LDAP requests to serve, with strong search
|
||||
* comparing both msgid and request pointer
|
||||
*/
|
||||
static int linphone_ldap_request_entry_compare_strong(const void*a, const void* b)
|
||||
{
|
||||
const LinphoneLDAPContactSearch* ra = (const LinphoneLDAPContactSearch*)a;
|
||||
const LinphoneLDAPContactSearch* rb = (const LinphoneLDAPContactSearch*)b;
|
||||
return !(ra->msgid == rb->msgid) && !(ra == rb);
|
||||
}
|
||||
|
||||
static inline LinphoneLDAPContactSearch* linphone_ldap_contact_provider_request_search( LinphoneLDAPContactProvider* obj, int msgid )
|
||||
{
|
||||
LinphoneLDAPContactSearch dummy = {};
|
||||
dummy.msgid = msgid;
|
||||
|
||||
MSList* list_entry = ms_list_find_custom(obj->requests, linphone_ldap_request_entry_compare_weak, &dummy);
|
||||
if( list_entry ) return list_entry->data;
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
static unsigned int linphone_ldap_contact_provider_cancel_search(LinphoneContactProvider* obj, LinphoneContactSearch *req)
|
||||
{
|
||||
LinphoneLDAPContactSearch* ldap_req = LINPHONE_LDAP_CONTACT_SEARCH(req);
|
||||
LinphoneLDAPContactProvider* ldap_cp = LINPHONE_LDAP_CONTACT_PROVIDER(obj);
|
||||
int ret = 1;
|
||||
|
||||
MSList* list_entry = ms_list_find_custom(ldap_cp->requests, linphone_ldap_request_entry_compare_strong, req);
|
||||
if( list_entry ) {
|
||||
ms_message("Delete search %p", req);
|
||||
ldap_cp->requests = ms_list_remove_link(ldap_cp->requests, list_entry);
|
||||
ldap_cp->req_count--;
|
||||
ret = 0; // return OK if we found it in the monitored requests
|
||||
} else {
|
||||
ms_warning("Couldn't find ldap request %p (id %d) in monitoring.", ldap_req, ldap_req->msgid);
|
||||
}
|
||||
belle_sip_object_unref(req); // unref request even if not found
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int linphone_ldap_contact_provider_perform_search( LinphoneLDAPContactProvider* obj, LinphoneLDAPContactSearch* req)
|
||||
{
|
||||
int ret = -1;
|
||||
struct timeval timeout = { obj->timeout, 0 };
|
||||
|
||||
if( req->msgid == 0 ){
|
||||
ms_message ( "Calling ldap_search_ext with predicate '%s' on base '%s', ld %p, attrs '%s', maxres = %d", req->filter, obj->base_object, obj->ld, obj->attributes[0], obj->max_results );
|
||||
ret = ldap_search_ext(obj->ld,
|
||||
obj->base_object,// base from which to start
|
||||
LDAP_SCOPE_SUBTREE,
|
||||
req->filter, // search predicate
|
||||
obj->attributes, // which attributes to get
|
||||
0, // 0 = get attrs AND value, 1 = get attrs only
|
||||
NULL,
|
||||
NULL,
|
||||
&timeout, // server timeout for the search
|
||||
obj->max_results,// max result number
|
||||
&req->msgid );
|
||||
|
||||
if( ret != LDAP_SUCCESS ){
|
||||
ms_error("Error ldap_search_ext returned %d (%s)", ret, ldap_err2string(ret));
|
||||
} else {
|
||||
ms_message("LinphoneLDAPContactSearch created @%p : msgid %d", req, req->msgid);
|
||||
}
|
||||
|
||||
} else {
|
||||
ms_warning( "LDAP Search already performed for %s, msgid %d", req->filter, req->msgid);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static LinphoneLDAPContactSearch* linphone_ldap_contact_provider_begin_search ( LinphoneLDAPContactProvider* obj,
|
||||
const char* predicate,
|
||||
ContactSearchCallback cb,
|
||||
void* cb_data )
|
||||
{
|
||||
bool_t connected = obj->connected;
|
||||
|
||||
// if we're not yet connected, bind
|
||||
if( !connected ) {
|
||||
if( !obj->bind_thread ) linphone_ldap_contact_provider_bind(obj);
|
||||
}
|
||||
|
||||
LinphoneLDAPContactSearch* request = linphone_ldap_contact_search_create( obj, predicate, cb, cb_data );
|
||||
|
||||
if( connected ){
|
||||
int ret = linphone_ldap_contact_provider_perform_search(obj, request);
|
||||
ms_message ( "Created search %d for '%s', msgid %d, @%p", obj->req_count, predicate, request->msgid, request );
|
||||
if( ret != LDAP_SUCCESS ){
|
||||
belle_sip_object_unref(request);
|
||||
request = NULL;
|
||||
}
|
||||
} else {
|
||||
ms_message("Delayed search, wait for connection");
|
||||
}
|
||||
|
||||
if( request != NULL ) {
|
||||
obj->requests = ms_list_append ( obj->requests, request );
|
||||
obj->req_count++;
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
static int linphone_ldap_contact_provider_marshal(LinphoneLDAPContactProvider* obj, char* buff, size_t buff_size, size_t *offset)
|
||||
{
|
||||
belle_sip_error_code error = BELLE_SIP_OK;
|
||||
|
||||
error = belle_sip_snprintf(buff, buff_size, offset, "ld:%p,\n", obj->ld);
|
||||
if(error!= BELLE_SIP_OK) return error;
|
||||
|
||||
error = belle_sip_snprintf(buff, buff_size, offset, "req_count:%d,\n", obj->req_count);
|
||||
if(error!= BELLE_SIP_OK) return error;
|
||||
|
||||
error = belle_sip_snprintf(buff, buff_size, offset,
|
||||
"CONFIG:\n"
|
||||
"tls: %d \n"
|
||||
"auth: %s \n"
|
||||
"user: %s \n"
|
||||
"pass: %s \n"
|
||||
"server: %s \n"
|
||||
"base: %s \n"
|
||||
"filter: %s \n"
|
||||
"timeout: %d \n"
|
||||
"deref: %d \n"
|
||||
"max_res: %d \n"
|
||||
"sip_attr:%s \n"
|
||||
"name_attr:%s \n"
|
||||
"attrs:\n",
|
||||
obj->use_tls, obj->auth_method,
|
||||
obj->username, obj->password, obj->server,
|
||||
obj->base_object, obj->filter,
|
||||
obj->timeout, obj->deref_aliases,
|
||||
obj->max_results,
|
||||
obj->sip_attr, obj->name_attr);
|
||||
if(error!= BELLE_SIP_OK) return error;
|
||||
|
||||
char **attr = obj->attributes;
|
||||
while( *attr ){
|
||||
error = belle_sip_snprintf(buff, buff_size, offset, "- %s\n", *attr);
|
||||
if(error!= BELLE_SIP_OK) return error;
|
||||
else attr++;
|
||||
}
|
||||
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
LinphoneLDAPContactProvider*linphone_ldap_contact_provider_ref(void* obj)
|
||||
{
|
||||
return linphone_ldap_contact_provider_cast(belle_sip_object_ref(obj));
|
||||
}
|
||||
|
||||
|
||||
void linphone_ldap_contact_provider_unref(void* obj)
|
||||
{
|
||||
belle_sip_object_unref(obj);
|
||||
}
|
||||
|
||||
inline LinphoneLDAPContactSearch*linphone_ldap_contact_search_cast(void* obj)
|
||||
{
|
||||
return BELLE_SIP_CAST(obj, LinphoneLDAPContactSearch);
|
||||
}
|
||||
|
||||
|
||||
LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast(void* obj)
|
||||
{
|
||||
return BELLE_SIP_CAST(obj, LinphoneLDAPContactProvider);
|
||||
}
|
||||
|
||||
int linphone_ldap_contact_provider_available()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneLDAPContactProvider);
|
||||
|
||||
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(LinphoneLDAPContactProvider)
|
||||
{
|
||||
{
|
||||
BELLE_SIP_VPTR_INIT(LinphoneLDAPContactProvider,LinphoneContactProvider,TRUE),
|
||||
(belle_sip_object_destroy_t)linphone_ldap_contact_provider_destroy,
|
||||
NULL,
|
||||
(belle_sip_object_marshal_t)linphone_ldap_contact_provider_marshal
|
||||
},
|
||||
"LDAP",
|
||||
(LinphoneContactProviderStartSearchMethod)linphone_ldap_contact_provider_begin_search,
|
||||
(LinphoneContactProviderCancelSearchMethod)linphone_ldap_contact_provider_cancel_search
|
||||
}
|
||||
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
|
||||
|
||||
#else
|
||||
|
||||
/* Stubbed implementation */
|
||||
|
||||
LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* ld,
|
||||
const char* predicate,
|
||||
ContactSearchCallback cb,
|
||||
void* cb_data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj){ return 0; }
|
||||
LinphoneLDAPContactSearch* linphone_ldap_contact_search_cast( void* obj ){ return NULL; }
|
||||
|
||||
|
||||
/* LinphoneLDAPContactProvider */
|
||||
|
||||
LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config){ return NULL; }
|
||||
unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj){ return 0; }
|
||||
LinphoneLDAPContactProvider* linphone_ldap_contact_provider_ref( void* obj ){ return NULL; }
|
||||
void linphone_ldap_contact_provider_unref( void* obj ){ }
|
||||
LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast( void* obj ){ return NULL; }
|
||||
|
||||
int linphone_ldap_contact_provider_available(){ return 0; }
|
||||
|
||||
|
||||
#endif /* BUILD_LDAP */
|
||||
|
||||
41
coreapi/ldap/ldapprovider.h
Normal file
41
coreapi/ldap/ldapprovider.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 Library 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 "contactprovider.h"
|
||||
|
||||
|
||||
typedef struct _LinphoneLDAPContactProvider LinphoneLDAPContactProvider;
|
||||
|
||||
/* LinphoneLDAPContactSearch */
|
||||
typedef struct _LinphoneLDAPContactSearch LinphoneLDAPContactSearch;
|
||||
|
||||
LinphoneLDAPContactSearch* linphone_ldap_contact_search_create(LinphoneLDAPContactProvider* ld,
|
||||
const char* predicate,
|
||||
ContactSearchCallback cb,
|
||||
void* cb_data);
|
||||
|
||||
unsigned int linphone_ldap_contact_search_result_count(LinphoneLDAPContactSearch* obj);
|
||||
LinphoneLDAPContactSearch* linphone_ldap_contact_search_cast( void* obj );
|
||||
|
||||
|
||||
/* LinphoneLDAPContactProvider */
|
||||
|
||||
LinphoneLDAPContactProvider* linphone_ldap_contact_provider_create(LinphoneCore* lc, const LinphoneDictionary* config);
|
||||
unsigned int linphone_ldap_contact_provider_get_max_result(const LinphoneLDAPContactProvider* obj);
|
||||
LinphoneLDAPContactProvider* linphone_ldap_contact_provider_ref( void* obj );
|
||||
void linphone_ldap_contact_provider_unref( void* obj );
|
||||
LinphoneLDAPContactProvider* linphone_ldap_contact_provider_cast( void* obj );
|
||||
int linphone_ldap_contact_provider_available();
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "ortp/payloadtype.h"
|
||||
#include "mediastreamer2/mscommon.h"
|
||||
#include "mediastreamer2/msvideo.h"
|
||||
#include "mediastreamer2/mediastream.h"
|
||||
|
||||
#ifdef IN_LINPHONE
|
||||
#include "sipsetup.h"
|
||||
|
|
@ -91,6 +92,7 @@ typedef struct _LCSipTransports{
|
|||
|
||||
/**
|
||||
* Enum describing transport type for LinphoneAddress.
|
||||
* @ingroup linphone_address
|
||||
**/
|
||||
enum _LinphoneTransportType{
|
||||
LinphoneTransportUdp,
|
||||
|
|
@ -100,6 +102,10 @@ enum _LinphoneTransportType{
|
|||
};
|
||||
/*this enum MUST be kept in sync with the SalTransport from sal.h*/
|
||||
|
||||
/**
|
||||
* Typedef for transport type enum.
|
||||
* @ingroup linphone_address
|
||||
**/
|
||||
typedef enum _LinphoneTransportType LinphoneTransportType;
|
||||
|
||||
/**
|
||||
|
|
@ -118,6 +124,8 @@ typedef enum _LinphoneTransportType LinphoneTransportType;
|
|||
*/
|
||||
typedef struct SalAddress LinphoneAddress;
|
||||
|
||||
typedef struct belle_sip_dict LinphoneDictionary;
|
||||
|
||||
/**
|
||||
* The LinphoneContent struct holds data that can be embedded in a signaling message.
|
||||
* @ingroup misc
|
||||
|
|
@ -151,24 +159,38 @@ typedef struct _LinphoneCall LinphoneCall;
|
|||
* Enum describing various failure reasons or contextual information for some events.
|
||||
* @see linphone_call_get_reason()
|
||||
* @see linphone_proxy_config_get_error()
|
||||
* @see linphone_error_info_get_reason()
|
||||
* @ingroup misc
|
||||
**/
|
||||
enum _LinphoneReason{
|
||||
LinphoneReasonNone,
|
||||
LinphoneReasonNoResponse, /**<No response received from remote*/
|
||||
LinphoneReasonBadCredentials, /**<Authentication failed due to bad*/
|
||||
LinphoneReasonForbidden, /**<Authentication failed due to bad credentials or resource forbidden*/
|
||||
LinphoneReasonDeclined, /**<The call has been declined*/
|
||||
LinphoneReasonNotFound, /**<Destination of the calls was not found.*/
|
||||
LinphoneReasonNotAnswered, /**<The call was not answered in time*/
|
||||
LinphoneReasonNotFound, /**<Destination of the call was not found.*/
|
||||
LinphoneReasonNotAnswered, /**<The call was not answered in time (request timeout)*/
|
||||
LinphoneReasonBusy, /**<Phone line was busy */
|
||||
LinphoneReasonMedia, /**<Incompatible media */
|
||||
LinphoneReasonUnsupportedContent, /**<Unsupported content */
|
||||
LinphoneReasonIOError, /**<Transport error: connection failures, disconnections etc...*/
|
||||
LinphoneReasonDoNotDisturb, /**<Do not disturb reason*/
|
||||
LinphoneReasonUnauthorized, /**<Operation is unauthorized because missing credential*/
|
||||
LinphoneReasonNotAcceptable /**<Operation like call update rejected by peer*/
|
||||
|
||||
LinphoneReasonNotAcceptable, /**<Operation like call update rejected by peer*/
|
||||
LinphoneReasonNoMatch, /**<Operation could not be executed by server or remote client because it didn't have any context for it*/
|
||||
LinphoneReasonMovedPermanently, /**<Resource moved permanently*/
|
||||
LinphoneReasonGone, /**<Resource no longer exists*/
|
||||
LinphoneReasonTemporarilyUnavailable, /**<Temporarily unavailable*/
|
||||
LinphoneReasonAddressIncomplete, /**<Address incomplete*/
|
||||
LinphoneReasonNotImplemented, /**<Not implemented*/
|
||||
LinphoneReasonBadGateway, /**<Bad gateway*/
|
||||
LinphoneReasonServerTimeout, /**<Server timeout*/
|
||||
LinphoneReasonUnknown /**Unknown reason*/
|
||||
};
|
||||
|
||||
#define LinphoneReasonBadCredentials LinphoneReasonForbidden
|
||||
|
||||
/*for compatibility*/
|
||||
#define LinphoneReasonMedia LinphoneReasonUnsupportedContent
|
||||
|
||||
/**
|
||||
* Enum describing failure reasons.
|
||||
* @ingroup misc
|
||||
|
|
@ -181,6 +203,49 @@ typedef enum _LinphoneReason LinphoneReason;
|
|||
**/
|
||||
const char *linphone_reason_to_string(LinphoneReason err);
|
||||
|
||||
/**
|
||||
* Object representing full details about a signaling error or status.
|
||||
* All LinphoneErrorInfo object returned by the liblinphone API are readonly and transcients. For safety they must be used immediately
|
||||
* after obtaining them. Any other function call to the liblinphone may change their content or invalidate the pointer.
|
||||
* @ingroup misc
|
||||
**/
|
||||
typedef struct _LinphoneErrorInfo LinphoneErrorInfo;
|
||||
|
||||
LINPHONE_PUBLIC LinphoneReason linphone_error_info_get_reason(const LinphoneErrorInfo *ei);
|
||||
LINPHONE_PUBLIC const char *linphone_error_info_get_phrase(const LinphoneErrorInfo *ei);
|
||||
LINPHONE_PUBLIC const char *linphone_error_info_get_details(const LinphoneErrorInfo *ei);
|
||||
LINPHONE_PUBLIC int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei);
|
||||
|
||||
/* linphone dictionary */
|
||||
LINPHONE_PUBLIC LinphoneDictionary* linphone_dictionary_new();
|
||||
LinphoneDictionary * linphone_dictionary_clone(const LinphoneDictionary* src);
|
||||
LinphoneDictionary * linphone_dictionary_ref(LinphoneDictionary* obj);
|
||||
void linphone_dictionary_unref(LinphoneDictionary* obj);
|
||||
LINPHONE_PUBLIC void linphone_dictionary_set_int(LinphoneDictionary* obj, const char* key, int value);
|
||||
LINPHONE_PUBLIC int linphone_dictionary_get_int(LinphoneDictionary* obj, const char* key, int default_value);
|
||||
LINPHONE_PUBLIC void linphone_dictionary_set_string(LinphoneDictionary* obj, const char* key, const char*value);
|
||||
LINPHONE_PUBLIC const char* linphone_dictionary_get_string(LinphoneDictionary* obj, const char* key, const char* default_value);
|
||||
LINPHONE_PUBLIC void linphone_dictionary_set_int64(LinphoneDictionary* obj, const char* key, int64_t value);
|
||||
LINPHONE_PUBLIC int64_t linphone_dictionary_get_int64(LinphoneDictionary* obj, const char* key, int64_t default_value);
|
||||
LINPHONE_PUBLIC int linphone_dictionary_remove(LinphoneDictionary* obj, const char* key);
|
||||
LINPHONE_PUBLIC void linphone_dictionary_clear(LinphoneDictionary* obj);
|
||||
LINPHONE_PUBLIC int linphone_dictionary_haskey(const LinphoneDictionary* obj, const char* key);
|
||||
LINPHONE_PUBLIC void linphone_dictionary_foreach( const LinphoneDictionary* obj, void (*apply_func)(const char*key, void* value, void* userdata), void* userdata);
|
||||
/**
|
||||
* Converts a config section into a dictionary.
|
||||
* @return a #LinphoneDictionary with all the keys from a section, or NULL if the section doesn't exist
|
||||
* @ingroup misc
|
||||
*/
|
||||
LinphoneDictionary* lp_config_section_to_dict( const LpConfig* lpconfig, const char* section );
|
||||
|
||||
/**
|
||||
* Loads a dictionary into a section of the lpconfig. If the section doesn't exist it is created.
|
||||
* Overwrites existing keys, creates non-existing keys.
|
||||
* @ingroup misc
|
||||
*/
|
||||
void lp_config_load_dict_to_section( LpConfig* lpconfig, const char* section, const LinphoneDictionary* dict);
|
||||
|
||||
|
||||
#ifdef IN_LINPHONE
|
||||
#include "linphonefriend.h"
|
||||
#include "event.h"
|
||||
|
|
@ -190,10 +255,10 @@ const char *linphone_reason_to_string(LinphoneReason err);
|
|||
#endif
|
||||
|
||||
LINPHONE_PUBLIC LinphoneAddress * linphone_address_new(const char *addr);
|
||||
LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr);
|
||||
LinphoneAddress * linphone_address_ref(LinphoneAddress *addr);
|
||||
void linphone_address_unref(LinphoneAddress *addr);
|
||||
const char *linphone_address_get_scheme(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr);
|
||||
LINPHONE_PUBLIC LinphoneAddress * linphone_address_ref(LinphoneAddress *addr);
|
||||
LINPHONE_PUBLIC void linphone_address_unref(LinphoneAddress *addr);
|
||||
LINPHONE_PUBLIC const char *linphone_address_get_scheme(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC const char *linphone_address_get_display_name(const LinphoneAddress* u);
|
||||
LINPHONE_PUBLIC const char *linphone_address_get_username(const LinphoneAddress *u);
|
||||
LINPHONE_PUBLIC const char *linphone_address_get_domain(const LinphoneAddress *u);
|
||||
|
|
@ -274,6 +339,12 @@ enum _LinphoneMediaEncryption {
|
|||
**/
|
||||
typedef enum _LinphoneMediaEncryption LinphoneMediaEncryption;
|
||||
|
||||
/**
|
||||
* Convert enum member to string.
|
||||
* @ingroup media_parameters
|
||||
**/
|
||||
LINPHONE_PUBLIC const char *linphone_media_encryption_to_string(LinphoneMediaEncryption menc);
|
||||
|
||||
/*public: */
|
||||
LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_from(LinphoneCallLog *cl);
|
||||
LINPHONE_PUBLIC LinphoneAddress *linphone_call_log_get_to(LinphoneCallLog *cl);
|
||||
|
|
@ -323,6 +394,8 @@ LINPHONE_PUBLIC bool_t linphone_call_params_low_bandwidth_enabled(const Linphone
|
|||
LINPHONE_PUBLIC void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t enabled);
|
||||
LINPHONE_PUBLIC void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path);
|
||||
LINPHONE_PUBLIC const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp);
|
||||
LINPHONE_PUBLIC const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp);
|
||||
LINPHONE_PUBLIC void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *subject);
|
||||
|
||||
/**
|
||||
* Add a custom SIP header in the INVITE for a call.
|
||||
|
|
@ -402,7 +475,7 @@ typedef enum _LinphonePrivacy {
|
|||
*
|
||||
**/
|
||||
LinphonePrivacyCritical=0x10,
|
||||
|
||||
|
||||
/**
|
||||
* Special keyword to use privacy as defined either globally or by proxy using linphone_proxy_config_set_privacy()
|
||||
*/
|
||||
|
|
@ -442,7 +515,7 @@ LINPHONE_PUBLIC LinphoneInfoMessage *linphone_info_message_copy(const LinphoneIn
|
|||
* @ingroup media_parameters
|
||||
**/
|
||||
struct _LinphoneVideoPolicy{
|
||||
bool_t automatically_initiate; /**<Whether video shall be automatically proposed for outgoing calls.*/
|
||||
bool_t automatically_initiate; /**<Whether video shall be automatically proposed for outgoing calls.*/
|
||||
bool_t automatically_accept; /**<Whether video shall be automatically accepted for incoming calls*/
|
||||
bool_t unused[2];
|
||||
};
|
||||
|
|
@ -505,6 +578,10 @@ enum _LinphoneUpnpState{
|
|||
typedef enum _LinphoneUpnpState LinphoneUpnpState;
|
||||
|
||||
|
||||
#define LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE (1 << 0) /**< received_rtcp field of LinphoneCallStats object has been updated */
|
||||
#define LINPHONE_CALL_STATS_SENT_RTCP_UPDATE (1 << 1) /**< sent_rtcp field of LinphoneCallStats object has been updated */
|
||||
|
||||
|
||||
/**
|
||||
* The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams.
|
||||
*
|
||||
|
|
@ -535,6 +612,7 @@ struct _LinphoneCallStats {
|
|||
float upload_bandwidth; /**<Download bandwidth measurement of sent stream, expressed in kbit/s, including IP/UDP/RTP headers*/
|
||||
float local_late_rate; /**<percentage of packet received too late over last second*/
|
||||
float local_loss_rate; /**<percentage of lost packet over last second*/
|
||||
int updated; /**< Tell which RTCP packet has been updated (received_rtcp or sent_rtcp). Can be either LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE or LINPHONE_CALL_STATS_SENT_RTCP_UPDATE */
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -543,7 +621,11 @@ struct _LinphoneCallStats {
|
|||
|
||||
LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call);
|
||||
|
||||
LINPHONE_PUBLIC float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats);
|
||||
LINPHONE_PUBLIC float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats);
|
||||
LINPHONE_PUBLIC float linphone_call_stats_get_sender_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call);
|
||||
LINPHONE_PUBLIC float linphone_call_stats_get_receiver_interarrival_jitter(const LinphoneCallStats *stats, LinphoneCall *call);
|
||||
LINPHONE_PUBLIC uint64_t linphone_call_stats_get_late_packets_cumulative_number(const LinphoneCallStats *stats, LinphoneCall *call);
|
||||
|
||||
/** Callback prototype */
|
||||
typedef void (*LinphoneCallCbFunc)(LinphoneCall *call,void * user_data);
|
||||
|
|
@ -579,7 +661,7 @@ LINPHONE_PUBLIC const char *linphone_call_state_to_string(LinphoneCallState cs);
|
|||
|
||||
LINPHONE_PUBLIC LinphoneCore *linphone_call_get_core(const LinphoneCall *call);
|
||||
LINPHONE_PUBLIC LinphoneCallState linphone_call_get_state(const LinphoneCall *call);
|
||||
bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC const LinphoneAddress * linphone_core_get_current_call_remote_address(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call);
|
||||
LINPHONE_PUBLIC char *linphone_call_get_remote_address_as_string(const LinphoneCall *call);
|
||||
|
|
@ -599,8 +681,10 @@ LINPHONE_PUBLIC void linphone_call_enable_camera(LinphoneCall *lc, bool_t enable
|
|||
LINPHONE_PUBLIC bool_t linphone_call_camera_enabled(const LinphoneCall *lc);
|
||||
LINPHONE_PUBLIC int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file);
|
||||
LINPHONE_PUBLIC LinphoneReason linphone_call_get_reason(const LinphoneCall *call);
|
||||
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_call_get_error_info(const LinphoneCall *call);
|
||||
LINPHONE_PUBLIC const char *linphone_call_get_remote_user_agent(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC LinphoneAddress *linphone_call_get_remote_contact_address(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC float linphone_call_get_play_volume(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC float linphone_call_get_record_volume(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC float linphone_call_get_current_quality(LinphoneCall *call);
|
||||
|
|
@ -616,6 +700,7 @@ LINPHONE_PUBLIC LinphoneCallState linphone_call_get_transfer_state(LinphoneCall
|
|||
LINPHONE_PUBLIC void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy);
|
||||
LINPHONE_PUBLIC void linphone_call_start_recording(LinphoneCall *call);
|
||||
LINPHONE_PUBLIC void linphone_call_stop_recording(LinphoneCall *call);
|
||||
|
||||
/**
|
||||
* Return TRUE if this call is currently part of a conference
|
||||
* @param call #LinphoneCall
|
||||
|
|
@ -752,13 +837,15 @@ LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProx
|
|||
LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj);
|
||||
LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj);
|
||||
LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params);
|
||||
LINPHONE_PUBLIC void linphone_proxy_config_set_contact_uri_parameters(LinphoneProxyConfig *obj, const char *contact_uri_params);
|
||||
LINPHONE_PUBLIC const char* linphone_proxy_config_get_contact_uri_parameters(const LinphoneProxyConfig *obj);
|
||||
|
||||
/**
|
||||
* Get the #LinphoneCore object to which is associated the #LinphoneProxyConfig.
|
||||
* @param[in] obj #LinphoneProxyConfig object.
|
||||
* @returns The #LinphoneCore object to which is associated the #LinphoneProxyConfig.
|
||||
**/
|
||||
LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj);
|
||||
LINPHONE_PUBLIC LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj);
|
||||
|
||||
LINPHONE_PUBLIC bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg);
|
||||
LINPHONE_PUBLIC const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg);
|
||||
|
|
@ -768,7 +855,14 @@ LINPHONE_PUBLIC const char * linphone_proxy_config_get_dial_prefix(const Linphon
|
|||
* @param[in] cfg #LinphoneProxyConfig object.
|
||||
* @returns The reason why registration failed for this proxy config.
|
||||
**/
|
||||
LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg);
|
||||
LINPHONE_PUBLIC LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg);
|
||||
|
||||
/**
|
||||
* Get detailed information why registration failed when the proxy config state is LinphoneRegistrationFailed.
|
||||
* @param[in] cfg #LinphoneProxyConfig object.
|
||||
* @returns The details why registration failed for this proxy config.
|
||||
**/
|
||||
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProxyConfig *cfg);
|
||||
|
||||
/*
|
||||
* return the transport from either : service route, route, or addr
|
||||
|
|
@ -779,10 +873,10 @@ LINPHONE_PUBLIC const char* linphone_proxy_config_get_transport(const LinphonePr
|
|||
|
||||
|
||||
/* destruction is called automatically when removing the proxy config */
|
||||
void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg);
|
||||
void linphone_proxy_config_set_sip_setup(LinphoneProxyConfig *cfg, const char *type);
|
||||
LINPHONE_PUBLIC void linphone_proxy_config_destroy(LinphoneProxyConfig *cfg);
|
||||
LINPHONE_PUBLIC void linphone_proxy_config_set_sip_setup(LinphoneProxyConfig *cfg, const char *type);
|
||||
SipSetupContext *linphone_proxy_config_get_sip_setup_context(LinphoneProxyConfig *cfg);
|
||||
SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg);
|
||||
LINPHONE_PUBLIC SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg);
|
||||
/**
|
||||
* normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222
|
||||
*/
|
||||
|
|
@ -869,6 +963,13 @@ typedef struct _LinphoneAuthInfo LinphoneAuthInfo;
|
|||
|
||||
LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid,
|
||||
const char *passwd, const char *ha1,const char *realm, const char *domain);
|
||||
/**
|
||||
* @addtogroup authentication
|
||||
* Instanciate a new auth info with values from source
|
||||
* @param source auth info object to be cloned
|
||||
* @return newly created auth info
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo* source);
|
||||
LINPHONE_PUBLIC void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd);
|
||||
LINPHONE_PUBLIC void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username);
|
||||
LINPHONE_PUBLIC void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid);
|
||||
|
|
@ -884,8 +985,8 @@ LINPHONE_PUBLIC const char *linphone_auth_info_get_domain(const LinphoneAuthInfo
|
|||
LINPHONE_PUBLIC const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i);
|
||||
|
||||
/* you don't need those function*/
|
||||
void linphone_auth_info_destroy(LinphoneAuthInfo *info);
|
||||
LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos);
|
||||
LINPHONE_PUBLIC void linphone_auth_info_destroy(LinphoneAuthInfo *info);
|
||||
LINPHONE_PUBLIC LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos);
|
||||
|
||||
|
||||
struct _LinphoneChatRoom;
|
||||
|
|
@ -899,7 +1000,7 @@ struct _LinphoneChatRoom;
|
|||
* <br> Can be created by linphone_chat_room_create_message().
|
||||
*/
|
||||
typedef struct _LinphoneChatMessage LinphoneChatMessage;
|
||||
|
||||
|
||||
/**
|
||||
* A chat room is the place where text messages are exchanged.
|
||||
* <br> Can be created by linphone_core_create_chat_room().
|
||||
|
|
@ -928,6 +1029,9 @@ LINPHONE_PUBLIC void linphone_core_set_chat_database_path(LinphoneCore *lc, cons
|
|||
LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to);
|
||||
LINPHONE_PUBLIC LinphoneChatRoom * linphone_core_get_or_create_chat_room(LinphoneCore *lc, const char *to);
|
||||
LINPHONE_PUBLIC LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr);
|
||||
LINPHONE_PUBLIC void linphone_core_disable_chat(LinphoneCore *lc, LinphoneReason deny_reason);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_chat(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_chat_enabled(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_chat_room_destroy(LinphoneChatRoom *cr);
|
||||
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr,const char* message);
|
||||
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_room_create_message_2(LinphoneChatRoom *cr, const char* message, const char* external_body_url, LinphoneChatMessageState state, time_t time, bool_t is_read, bool_t is_incoming);
|
||||
|
|
@ -939,16 +1043,32 @@ LINPHONE_PUBLIC MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int
|
|||
LINPHONE_PUBLIC void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr);
|
||||
LINPHONE_PUBLIC void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg);
|
||||
LINPHONE_PUBLIC void linphone_chat_room_delete_history(LinphoneChatRoom *cr);
|
||||
|
||||
/**
|
||||
* Notify the destination of the chat message being composed that the user is typing a new message.
|
||||
* @param[in] cr The #LinphoneChatRoom object corresponding to the conversation for which a new message is being typed.
|
||||
*/
|
||||
LINPHONE_PUBLIC void linphone_chat_room_compose(LinphoneChatRoom *cr);
|
||||
|
||||
/**
|
||||
* Tells whether the remote is currently composing a message.
|
||||
* @param[in] cr The "LinphoneChatRoom object corresponding to the conversation.
|
||||
* @return TRUE if the remote is currently composing a message, FALSE otherwise.
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr);
|
||||
LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr);
|
||||
LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud);
|
||||
LINPHONE_PUBLIC void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr);
|
||||
LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC unsigned int linphone_chat_message_store(LinphoneChatMessage *msg);
|
||||
|
||||
LINPHONE_PUBLIC const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state);
|
||||
LINPHONE_PUBLIC LinphoneChatMessageState linphone_chat_message_get_state(const LinphoneChatMessage* message);
|
||||
LINPHONE_PUBLIC LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* message);
|
||||
LINPHONE_PUBLIC LinphoneChatMessage * linphone_chat_message_ref(LinphoneChatMessage *msg);
|
||||
LINPHONE_PUBLIC void linphone_chat_message_unref(LinphoneChatMessage *msg);
|
||||
LINPHONE_PUBLIC void linphone_chat_message_destroy(LinphoneChatMessage* msg);
|
||||
LINPHONE_PUBLIC void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from);
|
||||
LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message);
|
||||
|
|
@ -968,6 +1088,8 @@ LINPHONE_PUBLIC const char * linphone_chat_message_get_custom_header(LinphoneCha
|
|||
LINPHONE_PUBLIC bool_t linphone_chat_message_is_read(LinphoneChatMessage* message);
|
||||
LINPHONE_PUBLIC bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message);
|
||||
LINPHONE_PUBLIC unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message);
|
||||
LINPHONE_PUBLIC LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg);
|
||||
LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_chat_message_get_error_info(const LinphoneChatMessage *msg);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
@ -986,7 +1108,8 @@ typedef enum _LinphoneGlobalState{
|
|||
LinphoneGlobalOff,
|
||||
LinphoneGlobalStartup,
|
||||
LinphoneGlobalOn,
|
||||
LinphoneGlobalShutdown
|
||||
LinphoneGlobalShutdown,
|
||||
LinphoneGlobalConfiguring
|
||||
}LinphoneGlobalState;
|
||||
|
||||
const char *linphone_global_state_to_string(LinphoneGlobalState gs);
|
||||
|
|
@ -1021,23 +1144,23 @@ typedef void (*LinphoneCoreCallEncryptionChangedCb)(LinphoneCore *lc, LinphoneCa
|
|||
* Registration state notification callback prototype
|
||||
* */
|
||||
typedef void (*LinphoneCoreRegistrationStateChangedCb)(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message);
|
||||
/** Callback prototype
|
||||
* @deprecated
|
||||
/** Callback prototype
|
||||
* @deprecated
|
||||
*/
|
||||
typedef void (*ShowInterfaceCb)(LinphoneCore *lc);
|
||||
/** Callback prototype
|
||||
* @deprecated
|
||||
/** Callback prototype
|
||||
* @deprecated
|
||||
*/
|
||||
typedef void (*DisplayStatusCb)(LinphoneCore *lc, const char *message);
|
||||
/** Callback prototype
|
||||
* @deprecated
|
||||
/** Callback prototype
|
||||
* @deprecated
|
||||
*/
|
||||
typedef void (*DisplayMessageCb)(LinphoneCore *lc, const char *message);
|
||||
/** Callback prototype
|
||||
* @deprecated
|
||||
/** Callback prototype
|
||||
* @deprecated
|
||||
*/
|
||||
typedef void (*DisplayUrlCb)(LinphoneCore *lc, const char *message, const char *url);
|
||||
/** Callback prototype
|
||||
/** Callback prototype
|
||||
*/
|
||||
typedef void (*LinphoneCoreCbFunc)(LinphoneCore *lc,void * user_data);
|
||||
/**
|
||||
|
|
@ -1055,7 +1178,7 @@ typedef void (*LinphoneCoreNotifyPresenceReceivedCb)(LinphoneCore *lc, LinphoneF
|
|||
* Callback prototype
|
||||
*/
|
||||
typedef void (*LinphoneCoreNewSubscriptionRequestedCb)(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
|
||||
/**
|
||||
/**
|
||||
* Callback for requesting authentication information to application or user.
|
||||
* @param lc the LinphoneCore
|
||||
* @param realm the realm (domain) on which authentication is required.
|
||||
|
|
@ -1064,7 +1187,7 @@ typedef void (*LinphoneCoreNewSubscriptionRequestedCb)(LinphoneCore *lc, Linphon
|
|||
*/
|
||||
typedef void (*LinphoneCoreAuthInfoRequestedCb)(LinphoneCore *lc, const char *realm, const char *username, const char *domain);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Callback to notify a new call-log entry has been added.
|
||||
* This is done typically when a call terminates.
|
||||
* @param lc the LinphoneCore
|
||||
|
|
@ -1091,8 +1214,16 @@ typedef void (*LinphoneCoreTextMessageReceivedCb)(LinphoneCore *lc, LinphoneChat
|
|||
* @param LinphoneChatMessage incoming message
|
||||
*/
|
||||
typedef void (*LinphoneCoreMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Is composing notification callback prototype.
|
||||
*
|
||||
* @param[in] lc #LinphoneCore object
|
||||
* @param[in] room #LinphoneChatRoom involved in the conversation.
|
||||
*/
|
||||
typedef void (*LinphoneCoreIsComposingReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room);
|
||||
|
||||
/**
|
||||
* Callback for being notified of DTMFs received.
|
||||
* @param lc the linphone core
|
||||
* @param call the call that received the dtmf
|
||||
|
|
@ -1112,7 +1243,7 @@ typedef void (*LinphoneCoreBuddyInfoUpdatedCb)(LinphoneCore *lc, LinphoneFriend
|
|||
*/
|
||||
typedef void (*LinphoneCoreTransferStateChangedCb)(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Callback for receiving quality statistics for calls.
|
||||
* @param lc the LinphoneCore
|
||||
* @param call the call
|
||||
|
|
@ -1120,14 +1251,31 @@ typedef void (*LinphoneCoreTransferStateChangedCb)(LinphoneCore *lc, LinphoneCal
|
|||
*/
|
||||
typedef void (*LinphoneCoreCallStatsUpdatedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Callback prototype for receiving info messages.
|
||||
* @param lc the LinphoneCore
|
||||
* @param call the call whose info message belongs to.
|
||||
* @param msg the info message.
|
||||
* @param msg the info message.
|
||||
*/
|
||||
typedef void (*LinphoneCoreInfoReceivedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg);
|
||||
|
||||
/**
|
||||
* LinphoneGlobalState describes the global state of the LinphoneCore object.
|
||||
* It is notified via the LinphoneCoreVTable::global_state_changed
|
||||
**/
|
||||
typedef enum _LinphoneConfiguringState {
|
||||
LinphoneConfiguringSuccessful,
|
||||
LinphoneConfiguringFailed,
|
||||
LinphoneConfiguringSkipped
|
||||
} LinphoneConfiguringState;
|
||||
|
||||
/**
|
||||
* Callback prototype for configuring status changes notification
|
||||
* @param lc the LinphoneCore
|
||||
* @param message informational message.
|
||||
*/
|
||||
typedef void (*LinphoneCoreConfiguringStatusCb)(LinphoneCore *lc, LinphoneConfiguringState status, const char *message);
|
||||
|
||||
/**
|
||||
* This structure holds all callbacks that the application should implement.
|
||||
* None is mandatory.
|
||||
|
|
@ -1141,6 +1289,7 @@ typedef struct _LinphoneCoreVTable{
|
|||
LinphoneCoreAuthInfoRequestedCb auth_info_requested; /**< Ask the application some authentication information */
|
||||
LinphoneCoreCallLogUpdatedCb call_log_updated; /**< Notifies that call log list has been updated */
|
||||
LinphoneCoreMessageReceivedCb message_received; /** a message is received, can be text or external body*/
|
||||
LinphoneCoreIsComposingReceivedCb is_composing_received; /**< An is-composing notification has been received */
|
||||
LinphoneCoreDtmfReceivedCb dtmf_received; /**< A dtmf has been received received */
|
||||
LinphoneCoreReferReceivedCb refer_received; /**< An out of call refer was received */
|
||||
LinphoneCoreCallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
|
||||
|
|
@ -1151,6 +1300,7 @@ typedef struct _LinphoneCoreVTable{
|
|||
LinphoneCoreSubscriptionStateChangedCb subscription_state_changed; /**<Notifies subscription state change */
|
||||
LinphoneCoreNotifyReceivedCb notify_received; /**< Notifies a an event notification, see linphone_core_subscribe() */
|
||||
LinphoneCorePublishStateChangedCb publish_state_changed;/**Notifies publish state change (only from #LinphoneEvent api)*/
|
||||
LinphoneCoreConfiguringStatusCb configuring_status; /** Notifies configuring status changes */
|
||||
DisplayStatusCb display_status; /**< @deprecated Callback that notifies various events with human readable text.*/
|
||||
DisplayMessageCb display_message;/**< @deprecated Callback to display a message to the user */
|
||||
DisplayMessageCb display_warning;/**< @deprecated Callback to display a warning to the user */
|
||||
|
|
@ -1284,6 +1434,8 @@ LINPHONE_PUBLIC int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *
|
|||
|
||||
LINPHONE_PUBLIC int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest);
|
||||
|
||||
LINPHONE_PUBLIC LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params);
|
||||
|
||||
LINPHONE_PUBLIC bool_t linphone_core_inc_invite_pending(LinphoneCore*lc);
|
||||
|
||||
LINPHONE_PUBLIC bool_t linphone_core_in_call(const LinphoneCore *lc);
|
||||
|
|
@ -1294,6 +1446,10 @@ LINPHONE_PUBLIC int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *ca
|
|||
|
||||
LINPHONE_PUBLIC int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, const LinphoneCallParams* params);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_accept_early_media(LinphoneCore* lc, LinphoneCall* call);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call);
|
||||
|
||||
/**
|
||||
|
|
@ -1339,8 +1495,8 @@ LINPHONE_PUBLIC const char *linphone_core_get_primary_contact(LinphoneCore *lc);
|
|||
|
||||
LINPHONE_PUBLIC const char * linphone_core_get_identity(LinphoneCore *lc);
|
||||
|
||||
void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val);
|
||||
bool_t linphone_core_get_guess_hostname(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_set_guess_hostname(LinphoneCore *lc, bool_t val);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_get_guess_hostname(LinphoneCore *lc);
|
||||
|
||||
LINPHONE_PUBLIC bool_t linphone_core_ipv6_enabled(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val);
|
||||
|
|
@ -1354,8 +1510,8 @@ LINPHONE_PUBLIC void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw
|
|||
LINPHONE_PUBLIC int linphone_core_get_download_bandwidth(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_get_upload_bandwidth(const LinphoneCore *lc);
|
||||
|
||||
void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled);
|
||||
bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime);
|
||||
LINPHONE_PUBLIC int linphone_core_get_download_ptime(LinphoneCore *lc);
|
||||
|
|
@ -1383,11 +1539,11 @@ LINPHONE_PUBLIC bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc);
|
|||
/* returns a MSList of PayloadType */
|
||||
LINPHONE_PUBLIC const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc);
|
||||
|
||||
int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs);
|
||||
LINPHONE_PUBLIC int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs);
|
||||
/* returns a MSList of PayloadType */
|
||||
LINPHONE_PUBLIC const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc);
|
||||
|
||||
int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs);
|
||||
LINPHONE_PUBLIC int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs);
|
||||
|
||||
/**
|
||||
* Tells whether the specified payload type is enabled.
|
||||
|
|
@ -1427,7 +1583,7 @@ LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadT
|
|||
* @param rate can be #LINPHONE_FIND_PAYLOAD_IGNORE_RATE
|
||||
* @param channels number of channels, can be #LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS
|
||||
* @return Returns NULL if not found.
|
||||
*/
|
||||
*/
|
||||
LINPHONE_PUBLIC PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ;
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt);
|
||||
|
|
@ -1443,7 +1599,7 @@ LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *
|
|||
* @ingroup proxy
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc);
|
||||
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_clear_proxy_config(LinphoneCore *lc);
|
||||
|
|
@ -1489,7 +1645,7 @@ LINPHONE_PUBLIC void linphone_core_clear_all_auth_info(LinphoneCore *lc);
|
|||
* @param[in] enable TRUE to enable the audio adaptive jitter compensation, FALSE to disable it.
|
||||
* @ingroup media_parameters
|
||||
*/
|
||||
void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enable);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enable);
|
||||
|
||||
/**
|
||||
* Tells whether the audio adaptive jitter compensation is enabled.
|
||||
|
|
@ -1497,11 +1653,11 @@ void linphone_core_enable_audio_adaptive_jittcomp(LinphoneCore *lc, bool_t enabl
|
|||
* @returns TRUE if the audio adaptive jitter compensation is enabled, FALSE otherwise.
|
||||
* @ingroup media_parameters
|
||||
*/
|
||||
bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_audio_adaptive_jittcomp_enabled(LinphoneCore *lc);
|
||||
|
||||
int linphone_core_get_audio_jittcomp(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_get_audio_jittcomp(LinphoneCore *lc);
|
||||
|
||||
void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value);
|
||||
LINPHONE_PUBLIC void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value);
|
||||
|
||||
/**
|
||||
* Enable or disable the video adaptive jitter compensation.
|
||||
|
|
@ -1509,7 +1665,7 @@ void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value);
|
|||
* @param[in] enable TRUE to enable the video adaptive jitter compensation, FALSE to disable it.
|
||||
* @ingroup media_parameters
|
||||
*/
|
||||
void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enable);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enable);
|
||||
|
||||
/**
|
||||
* Tells whether the video adaptive jitter compensation is enabled.
|
||||
|
|
@ -1517,11 +1673,11 @@ void linphone_core_enable_video_adaptive_jittcomp(LinphoneCore *lc, bool_t enabl
|
|||
* @returns TRUE if the video adaptive jitter compensation is enabled, FALSE otherwise.
|
||||
* @ingroup media_parameters
|
||||
*/
|
||||
bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_video_adaptive_jittcomp_enabled(LinphoneCore *lc);
|
||||
|
||||
int linphone_core_get_video_jittcomp(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_get_video_jittcomp(LinphoneCore *lc);
|
||||
|
||||
void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value);
|
||||
LINPHONE_PUBLIC void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_get_audio_port(const LinphoneCore *lc);
|
||||
|
||||
|
|
@ -1559,6 +1715,8 @@ LINPHONE_PUBLIC int linphone_core_set_sip_transports(LinphoneCore *lc, const LCS
|
|||
|
||||
LINPHONE_PUBLIC int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *transports);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCSipTransports *tr);
|
||||
|
||||
LINPHONE_PUBLIC bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp);
|
||||
/**
|
||||
*
|
||||
|
|
@ -1600,30 +1758,30 @@ LINPHONE_PUBLIC const char * linphone_core_get_stun_server(const LinphoneCore *l
|
|||
* @ingroup network_parameters
|
||||
* Return the availability of uPnP.
|
||||
*
|
||||
* @return true if uPnP is available otherwise return false.
|
||||
* @return true if uPnP is available otherwise return false.
|
||||
*/
|
||||
bool_t linphone_core_upnp_available();
|
||||
LINPHONE_PUBLIC bool_t linphone_core_upnp_available();
|
||||
|
||||
/**
|
||||
* @ingroup network_parameters
|
||||
* Return the internal state of uPnP.
|
||||
* Return the internal state of uPnP.
|
||||
*
|
||||
* @param lc #LinphoneCore
|
||||
* @return an LinphoneUpnpState.
|
||||
* @return an LinphoneUpnpState.
|
||||
*/
|
||||
LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* @ingroup network_parameters
|
||||
* Return the external ip address of router.
|
||||
* Return the external ip address of router.
|
||||
* In some cases the uPnP can have an external ip address but not a usable uPnP
|
||||
* (state different of Ok).
|
||||
* (state different of Ok).
|
||||
*
|
||||
* @param lc #LinphoneCore
|
||||
* @return a null terminated string containing the external ip address. If the
|
||||
* the external ip address is not available return null.
|
||||
* the external ip address is not available return null.
|
||||
*/
|
||||
const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Set the public IP address of NAT when using the firewall policy is set to use NAT.
|
||||
|
|
@ -1631,7 +1789,7 @@ const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc);
|
|||
* @param[in] addr The public IP address of NAT to use.
|
||||
* @ingroup network_parameters
|
||||
*/
|
||||
void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr);
|
||||
LINPHONE_PUBLIC void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr);
|
||||
|
||||
/**
|
||||
* Get the public IP address of NAT being used.
|
||||
|
|
@ -1639,7 +1797,7 @@ void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr);
|
|||
* @returns The public IP address of NAT being used.
|
||||
* @ingroup network_parameters
|
||||
*/
|
||||
const char *linphone_core_get_nat_address(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC const char *linphone_core_get_nat_address(const LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Set the policy to use to pass through firewalls.
|
||||
|
|
@ -1659,7 +1817,7 @@ LINPHONE_PUBLIC LinphoneFirewallPolicy linphone_core_get_firewall_policy(const L
|
|||
|
||||
/* sound functions */
|
||||
/* returns a null terminated static array of string describing the sound devices */
|
||||
const char** linphone_core_get_sound_devices(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC const char** linphone_core_get_sound_devices(LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Update detection of sound devices.
|
||||
|
|
@ -1669,13 +1827,13 @@ const char** linphone_core_get_sound_devices(LinphoneCore *lc);
|
|||
* @param[in] lc #LinphoneCore object.
|
||||
* @ingroup media_parameters
|
||||
**/
|
||||
void linphone_core_reload_sound_devices(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_reload_sound_devices(LinphoneCore *lc);
|
||||
|
||||
bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *device);
|
||||
bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *device);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_sound_device_can_capture(LinphoneCore *lc, const char *device);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_sound_device_can_playback(LinphoneCore *lc, const char *device);
|
||||
LINPHONE_PUBLIC int linphone_core_get_ring_level(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_get_play_level(LinphoneCore *lc);
|
||||
int linphone_core_get_rec_level(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_get_rec_level(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_set_ring_level(LinphoneCore *lc, int level);
|
||||
LINPHONE_PUBLIC void linphone_core_set_play_level(LinphoneCore *lc, int level);
|
||||
|
||||
|
|
@ -1684,13 +1842,13 @@ LINPHONE_PUBLIC float linphone_core_get_mic_gain_db(LinphoneCore *lc);
|
|||
LINPHONE_PUBLIC void linphone_core_set_playback_gain_db(LinphoneCore *lc, float level);
|
||||
LINPHONE_PUBLIC float linphone_core_get_playback_gain_db(LinphoneCore *lc);
|
||||
|
||||
void linphone_core_set_rec_level(LinphoneCore *lc, int level);
|
||||
const char * linphone_core_get_ringer_device(LinphoneCore *lc);
|
||||
const char * linphone_core_get_playback_device(LinphoneCore *lc);
|
||||
const char * linphone_core_get_capture_device(LinphoneCore *lc);
|
||||
int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid);
|
||||
int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid);
|
||||
int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid);
|
||||
LINPHONE_PUBLIC void linphone_core_set_rec_level(LinphoneCore *lc, int level);
|
||||
LINPHONE_PUBLIC const char * linphone_core_get_ringer_device(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC const char * linphone_core_get_playback_device(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC const char * linphone_core_get_capture_device(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_set_ringer_device(LinphoneCore *lc, const char * devid);
|
||||
LINPHONE_PUBLIC int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid);
|
||||
LINPHONE_PUBLIC int linphone_core_set_capture_device(LinphoneCore *lc, const char * devid);
|
||||
char linphone_core_get_sound_source(LinphoneCore *lc);
|
||||
void linphone_core_set_sound_source(LinphoneCore *lc, char source);
|
||||
LINPHONE_PUBLIC void linphone_core_stop_ringing(LinphoneCore *lc);
|
||||
|
|
@ -1707,6 +1865,7 @@ LINPHONE_PUBLIC void linphone_core_set_remote_ringback_tone(LinphoneCore *lc,con
|
|||
LINPHONE_PUBLIC const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata);
|
||||
LINPHONE_PUBLIC int linphone_core_play_local(LinphoneCore *lc, const char *audiofile);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc);
|
||||
|
||||
|
|
@ -1867,8 +2026,8 @@ LINPHONE_PUBLIC void linphone_core_set_preferred_video_size(LinphoneCore *lc, MS
|
|||
LINPHONE_PUBLIC MSVideoSize linphone_core_get_preferred_video_size(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name);
|
||||
|
||||
void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val);
|
||||
bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_video_preview_enabled(const LinphoneCore *lc);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val);
|
||||
LINPHONE_PUBLIC bool_t linphone_core_self_view_enabled(const LinphoneCore *lc);
|
||||
|
|
@ -1882,7 +2041,7 @@ LINPHONE_PUBLIC bool_t linphone_core_self_view_enabled(const LinphoneCore *lc);
|
|||
* @param[in] lc #LinphoneCore object.
|
||||
* @ingroup media_parameters
|
||||
**/
|
||||
void linphone_core_reload_video_devices(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_reload_video_devices(LinphoneCore *lc);
|
||||
|
||||
/* returns a null terminated static array of string describing the webcams */
|
||||
LINPHONE_PUBLIC const char** linphone_core_get_video_devices(const LinphoneCore *lc);
|
||||
|
|
@ -1896,7 +2055,7 @@ LINPHONE_PUBLIC const char *linphone_core_get_video_device(const LinphoneCore *l
|
|||
* @param[in] path The path to the image file to use.
|
||||
* @ingroup media_parameters
|
||||
*/
|
||||
int linphone_core_set_static_picture(LinphoneCore *lc, const char *path);
|
||||
LINPHONE_PUBLIC int linphone_core_set_static_picture(LinphoneCore *lc, const char *path);
|
||||
|
||||
/**
|
||||
* Get the path to the image file streamed when "Static picture" is set as the video device.
|
||||
|
|
@ -1904,7 +2063,7 @@ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path);
|
|||
* @returns The path to the image file streamed when "Static picture" is set as the video device.
|
||||
* @ingroup media_parameters
|
||||
*/
|
||||
const char *linphone_core_get_static_picture(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC const char *linphone_core_get_static_picture(LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Set the frame rate for static picture.
|
||||
|
|
@ -1912,7 +2071,7 @@ const char *linphone_core_get_static_picture(LinphoneCore *lc);
|
|||
* @param[in] fps The new frame rate to use for static picture.
|
||||
* @ingroup media_parameters
|
||||
*/
|
||||
int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps);
|
||||
LINPHONE_PUBLIC int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps);
|
||||
|
||||
/**
|
||||
* Get the frame rate for static picture
|
||||
|
|
@ -1920,7 +2079,7 @@ int linphone_core_set_static_picture_fps(LinphoneCore *lc, float fps);
|
|||
* @return The frame rate used for static picture.
|
||||
* @ingroup media_parameters
|
||||
*/
|
||||
float linphone_core_get_static_picture_fps(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC float linphone_core_get_static_picture_fps(LinphoneCore *lc);
|
||||
|
||||
/*function to be used for eventually setting window decorations (icons, title...)*/
|
||||
LINPHONE_PUBLIC unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc);
|
||||
|
|
@ -1958,7 +2117,7 @@ void linphone_core_show_video(LinphoneCore *lc, bool_t show);
|
|||
/*play/record support: use files instead of soundcard*/
|
||||
void linphone_core_use_files(LinphoneCore *lc, bool_t yesno);
|
||||
LINPHONE_PUBLIC void linphone_core_set_play_file(LinphoneCore *lc, const char *file);
|
||||
void linphone_core_set_record_file(LinphoneCore *lc, const char *file);
|
||||
LINPHONE_PUBLIC void linphone_core_set_record_file(LinphoneCore *lc, const char *file);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms);
|
||||
LINPHONE_PUBLIC void linphone_core_stop_dtmf(LinphoneCore *lc);
|
||||
|
|
@ -1966,7 +2125,7 @@ LINPHONE_PUBLIC void linphone_core_stop_dtmf(LinphoneCore *lc);
|
|||
LINPHONE_PUBLIC int linphone_core_get_current_call_duration(const LinphoneCore *lc);
|
||||
|
||||
|
||||
int linphone_core_get_mtu(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC int linphone_core_get_mtu(const LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_set_mtu(LinphoneCore *lc, int mtu);
|
||||
|
||||
/**
|
||||
|
|
@ -2051,7 +2210,7 @@ LINPHONE_PUBLIC void linphone_core_refresh_registers(LinphoneCore* lc);
|
|||
* @param[in] file The path to the file to use to store the zrtp secrets cache.
|
||||
* @ingroup initializing
|
||||
*/
|
||||
void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file);
|
||||
LINPHONE_PUBLIC void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file);
|
||||
|
||||
/**
|
||||
* Get the path to the file storing the zrtp secrets cache.
|
||||
|
|
@ -2059,7 +2218,7 @@ void linphone_core_set_zrtp_secrets_file(LinphoneCore *lc, const char* file);
|
|||
* @returns The path to the file storing the zrtp secrets cache.
|
||||
* @ingroup initializing
|
||||
*/
|
||||
const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Search from the list of current calls if a remote address match uri
|
||||
|
|
@ -2162,7 +2321,84 @@ LINPHONE_PUBLIC int linphone_core_get_video_dscp(const LinphoneCore *lc);
|
|||
LINPHONE_PUBLIC const char *linphone_core_get_video_display_filter(LinphoneCore *lc);
|
||||
LINPHONE_PUBLIC void linphone_core_set_video_display_filter(LinphoneCore *lc, const char *filtername);
|
||||
|
||||
/** Contact Providers
|
||||
*/
|
||||
|
||||
typedef unsigned int ContactSearchID;
|
||||
|
||||
typedef struct _LinphoneContactSearch LinphoneContactSearch;
|
||||
typedef struct _LinphoneContactProvider LinphoneContactProvider;
|
||||
|
||||
typedef void (*ContactSearchCallback)( LinphoneContactSearch* id, MSList* friends, void* data );
|
||||
|
||||
/*
|
||||
* Remote provisioning
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set URI where to download xml configuration file at startup.
|
||||
* This can also be set from configuration file or factory config file, from [misc] section, item "config-uri".
|
||||
* Calling this function does not load the configuration. It will write the value into configuration so that configuration
|
||||
* from remote URI will take place at next LinphoneCore start.
|
||||
* @param lc the linphone core
|
||||
* @param uri the http or https uri to use in order to download the configuration.
|
||||
* @ingroup initializing
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char*uri);
|
||||
|
||||
/**
|
||||
* Get provisioning URI.
|
||||
* @param lc the linphone core
|
||||
* @return the provisioning URI.
|
||||
* @ingroup initializing
|
||||
**/
|
||||
LINPHONE_PUBLIC const char* linphone_core_get_provisioning_uri(const LinphoneCore *lc);
|
||||
|
||||
/**
|
||||
* Gets if the provisioning URI should be removed after it's been applied successfully
|
||||
* @param lc the linphone core
|
||||
* @return TRUE if the provisioning URI should be removed, FALSE otherwise
|
||||
*/
|
||||
LINPHONE_PUBLIC bool_t linphone_core_is_provisioning_transient(LinphoneCore *lc);
|
||||
|
||||
LINPHONE_PUBLIC int linphone_core_migrate_to_multi_transport(LinphoneCore *lc);
|
||||
|
||||
|
||||
/**
|
||||
* Control when media offer is sent in SIP INVITE.
|
||||
* @param lc the linphone core
|
||||
* @param enable true if INVITE has to be sent whitout SDP.
|
||||
* @ingroup network_parameters
|
||||
**/
|
||||
LINPHONE_PUBLIC void linphone_core_enable_sdp_200_ack(LinphoneCore *lc, bool_t enable);
|
||||
/**
|
||||
* Media offer control param for SIP INVITE.
|
||||
* @return true if INVITE has to be sent whitout SDP.
|
||||
* @ingroup network_parameters
|
||||
**/
|
||||
LINPHONE_PUBLIC bool_t linphone_core_sdp_200_ack_enabled(const LinphoneCore *lc);
|
||||
|
||||
|
||||
/**
|
||||
* Enum listing frequent telephony tones.
|
||||
**/
|
||||
enum _LinphoneToneID{
|
||||
LinphoneToneUndefined, /**<Not a tone */
|
||||
LinphoneToneBusy, /**<Busy tone */
|
||||
LinphoneToneCallWaiting, /**Call waiting tone */
|
||||
LinphoneToneCallOnHold, /**Call on hold tone */
|
||||
LinphoneToneCallLost /**Tone played when call is abruptly disconnected (media lost)*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum typedef for representing frequent telephony tones.
|
||||
**/
|
||||
typedef enum _LinphoneToneID LinphoneToneID;
|
||||
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, const char *audiofile);
|
||||
|
||||
LINPHONE_PUBLIC void linphone_core_set_tone(LinphoneCore *lc, LinphoneToneID id, const char *audiofile);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
extern "C" {
|
||||
#include "mediastreamer2/mediastream.h"
|
||||
#include "mediastreamer2/mscommon.h"
|
||||
}
|
||||
#include "mediastreamer2/msjava.h"
|
||||
#include "private.h"
|
||||
|
|
@ -39,6 +40,9 @@ extern "C" void libmsilbc_init();
|
|||
#ifdef HAVE_X264
|
||||
extern "C" void libmsx264_init();
|
||||
#endif
|
||||
#ifdef HAVE_OPENH264
|
||||
extern "C" void libmsopenh264_init();
|
||||
#endif
|
||||
#ifdef HAVE_AMR
|
||||
extern "C" void libmsamr_init();
|
||||
#endif
|
||||
|
|
@ -170,6 +174,7 @@ public:
|
|||
vTable.call_encryption_changed = callEncryptionChange;
|
||||
vTable.text_received = text_received;
|
||||
vTable.message_received = message_received;
|
||||
vTable.is_composing_received = is_composing_received;
|
||||
vTable.dtmf_received = dtmf_received;
|
||||
vTable.new_subscription_requested = new_subscription_requested;
|
||||
vTable.notify_presence_received = notify_presence_received;
|
||||
|
|
@ -179,6 +184,7 @@ public:
|
|||
vTable.subscription_state_changed=subscriptionStateChanged;
|
||||
vTable.notify_received=notifyReceived;
|
||||
vTable.publish_state_changed=publishStateChanged;
|
||||
vTable.configuring_status=configuringStatus;
|
||||
|
||||
listenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener));
|
||||
|
||||
|
|
@ -218,6 +224,8 @@ public:
|
|||
|
||||
/*void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)*/
|
||||
newSubscriptionRequestId = env->GetMethodID(listenerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V");
|
||||
|
||||
authInfoRequestedId = env->GetMethodID(listenerClass,"authInfoRequested","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||
|
||||
/*void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);*/
|
||||
notifyPresenceReceivedId = env->GetMethodID(listenerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;)V");
|
||||
|
|
@ -225,6 +233,7 @@ public:
|
|||
/*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/
|
||||
textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V");
|
||||
messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V");
|
||||
isComposingReceivedId = env->GetMethodID(listenerClass,"isComposingReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;)V");
|
||||
dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V");
|
||||
infoReceivedId = env->GetMethodID(listenerClass,"infoReceived",
|
||||
"(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneInfoMessage;)V");
|
||||
|
|
@ -238,7 +247,7 @@ public:
|
|||
|
||||
|
||||
proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl"));
|
||||
proxyCtrId = env->GetMethodID(proxyClass,"<init>", "(J)V");
|
||||
proxyCtrId = env->GetMethodID(proxyClass,"<init>", "(Lorg/linphone/core/LinphoneCoreImpl;J)V");
|
||||
|
||||
callClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallImpl"));
|
||||
callCtrId = env->GetMethodID(callClass,"<init>", "(J)V");
|
||||
|
|
@ -274,6 +283,10 @@ public:
|
|||
|
||||
subscriptionDirClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionDir"));
|
||||
subscriptionDirFromIntId = env->GetStaticMethodID(subscriptionDirClass,"fromInt","(I)Lorg/linphone/core/SubscriptionDir;");
|
||||
|
||||
configuringStateId = env->GetMethodID(listenerClass,"configuringStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;Ljava/lang/String;)V");
|
||||
configuringStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RemoteProvisioningState"));
|
||||
configuringStateFromIntId = env->GetStaticMethodID(configuringStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;");
|
||||
}
|
||||
|
||||
~LinphoneCoreData() {
|
||||
|
|
@ -284,6 +297,7 @@ public:
|
|||
if (userdata) env->DeleteGlobalRef(userdata);
|
||||
env->DeleteGlobalRef(listenerClass);
|
||||
env->DeleteGlobalRef(globalStateClass);
|
||||
env->DeleteGlobalRef(configuringStateClass);
|
||||
env->DeleteGlobalRef(registrationStateClass);
|
||||
env->DeleteGlobalRef(callStateClass);
|
||||
env->DeleteGlobalRef(chatMessageStateClass);
|
||||
|
|
@ -307,13 +321,19 @@ public:
|
|||
jmethodID notifyPresenceReceivedId;
|
||||
jmethodID textReceivedId;
|
||||
jmethodID messageReceivedId;
|
||||
jmethodID isComposingReceivedId;
|
||||
jmethodID dtmfReceivedId;
|
||||
jmethodID callStatsUpdatedId;
|
||||
jmethodID transferStateId;
|
||||
jmethodID infoReceivedId;
|
||||
jmethodID subscriptionStateId;
|
||||
jmethodID authInfoRequestedId;
|
||||
jmethodID publishStateId;
|
||||
jmethodID notifyRecvId;
|
||||
|
||||
jclass configuringStateClass;
|
||||
jmethodID configuringStateId;
|
||||
jmethodID configuringStateFromIntId;
|
||||
|
||||
jclass globalStateClass;
|
||||
jmethodID globalStateId;
|
||||
|
|
@ -396,7 +416,19 @@ public:
|
|||
|
||||
}
|
||||
static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
|
||||
|
||||
JNIEnv *env = 0;
|
||||
jint result = jvm->AttachCurrentThread(&env,NULL);
|
||||
if (result != 0) {
|
||||
ms_error("cannot attach VM");
|
||||
return;
|
||||
}
|
||||
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
|
||||
env->CallVoidMethod(lcData->listener,
|
||||
lcData->authInfoRequestedId,
|
||||
lcData->core,
|
||||
realm ? env->NewStringUTF(realm):NULL,
|
||||
username ? env->NewStringUTF(username) : NULL,
|
||||
domain ? env->NewStringUTF(domain) : NULL);
|
||||
}
|
||||
static void globalStateChange(LinphoneCore *lc, LinphoneGlobalState gstate,const char* message) {
|
||||
JNIEnv *env = 0;
|
||||
|
|
@ -423,7 +455,7 @@ public:
|
|||
env->CallVoidMethod(lcData->listener
|
||||
,lcData->registrationStateId
|
||||
,lcData->core
|
||||
,env->NewObject(lcData->proxyClass,lcData->proxyCtrId,(jlong)proxy)
|
||||
,env->NewObject(lcData->proxyClass,lcData->proxyCtrId,lcData->core,(jlong)proxy)
|
||||
,env->CallStaticObjectMethod(lcData->registrationStateClass,lcData->registrationStateFromIntId,(jint)state),
|
||||
message ? env->NewStringUTF(message) : NULL);
|
||||
}
|
||||
|
|
@ -550,6 +582,19 @@ public:
|
|||
,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room)
|
||||
,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg));
|
||||
}
|
||||
static void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) {
|
||||
JNIEnv *env = 0;
|
||||
jint result = jvm->AttachCurrentThread(&env,NULL);
|
||||
if (result != 0) {
|
||||
ms_error("cannot attach VM");
|
||||
return;
|
||||
}
|
||||
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
|
||||
env->CallVoidMethod(lcData->listener
|
||||
,lcData->isComposingReceivedId
|
||||
,lcData->core
|
||||
,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room));
|
||||
}
|
||||
static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) {
|
||||
JNIEnv *env = 0;
|
||||
jint result = jvm->AttachCurrentThread(&env,NULL);
|
||||
|
|
@ -692,6 +737,17 @@ public:
|
|||
,content ? create_java_linphone_content(env,content) : NULL
|
||||
);
|
||||
}
|
||||
|
||||
static void configuringStatus(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) {
|
||||
JNIEnv *env = 0;
|
||||
jint result = jvm->AttachCurrentThread(&env,NULL);
|
||||
if (result != 0) {
|
||||
ms_error("cannot attach VM");
|
||||
return;
|
||||
}
|
||||
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
|
||||
env->CallVoidMethod(lcData->listener, lcData->configuringStateId, lcData->core, env->CallStaticObjectMethod(lcData->configuringStateClass,lcData->configuringStateFromIntId,(jint)status), message ? env->NewStringUTF(message) : NULL);
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env
|
||||
|
|
@ -705,12 +761,17 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv*
|
|||
const char* factoryConfig = jfactoryConfig?env->GetStringUTFChars(jfactoryConfig, NULL):NULL;
|
||||
LinphoneCoreData* ldata = new LinphoneCoreData(env,thiz,jlistener,juserdata);
|
||||
|
||||
ms_init(); // Initialize mediastreamer2 before loading the plugins
|
||||
|
||||
#ifdef HAVE_ILBC
|
||||
libmsilbc_init(); // requires an fpu
|
||||
#endif
|
||||
#ifdef HAVE_X264
|
||||
libmsx264_init();
|
||||
#endif
|
||||
#ifdef HAVE_OPENH264
|
||||
libmsopenh264_init();
|
||||
#endif
|
||||
#ifdef HAVE_AMR
|
||||
libmsamr_init();
|
||||
#endif
|
||||
|
|
@ -739,9 +800,16 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env
|
|||
,jlong lc) {
|
||||
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc);
|
||||
linphone_core_destroy((LinphoneCore*)lc);
|
||||
ms_exit();
|
||||
delete lcData;
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_migrateToMultiTransport(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc) {
|
||||
return (jint) linphone_core_migrate_to_multi_transport((LinphoneCore *)lc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_LinphoneCoreImpl
|
||||
* Method: createInfoMessage
|
||||
|
|
@ -755,6 +823,10 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCallImpl_sendInfoMessage(J
|
|||
return linphone_call_send_info_message((LinphoneCall*)callptr,(LinphoneInfoMessage*)infoptr);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_stopRinging(JNIEnv* env, jobject thiz, jlong lc) {
|
||||
linphone_core_stop_ringing((LinphoneCore*)lc);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setChatDatabasePath(JNIEnv* env, jobject thiz, jlong lc, jstring jpath) {
|
||||
const char* path = env->GetStringUTFChars(jpath, NULL);
|
||||
linphone_core_set_chat_database_path((LinphoneCore*)lc, path);
|
||||
|
|
@ -762,8 +834,8 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setChatDatabasePath(JNIE
|
|||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv* env, jobject thiz, jlong lc, jstring jdisplayname, jstring jusername) {
|
||||
const char* displayname = env->GetStringUTFChars(jdisplayname, NULL);
|
||||
const char* username = env->GetStringUTFChars(jusername, NULL);
|
||||
const char* displayname = jdisplayname ? env->GetStringUTFChars(jdisplayname, NULL) : NULL;
|
||||
const char* username = jusername ? env->GetStringUTFChars(jusername, NULL) : NULL;
|
||||
|
||||
LinphoneAddress *parsed = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc);
|
||||
if (parsed != NULL) {
|
||||
|
|
@ -773,8 +845,8 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv
|
|||
linphone_core_set_primary_contact((LinphoneCore*)lc, contact);
|
||||
}
|
||||
|
||||
env->ReleaseStringUTFChars(jdisplayname, displayname);
|
||||
env->ReleaseStringUTFChars(jusername, username);
|
||||
if (jdisplayname) env->ReleaseStringUTFChars(jdisplayname, displayname);
|
||||
if (jusername) env->ReleaseStringUTFChars(jusername, username);
|
||||
}
|
||||
|
||||
extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getPrimaryContactUsername(JNIEnv* env, jobject thiz, jlong lc) {
|
||||
|
|
@ -972,6 +1044,21 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_deferCallUpdate(JNIEnv *
|
|||
linphone_core_defer_call_update((LinphoneCore*)lc,(LinphoneCall*)call);
|
||||
}
|
||||
|
||||
extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_acceptEarlyMedia(JNIEnv *env, jobject thiz, jlong lc, jlong c) {
|
||||
LinphoneCore *core = (LinphoneCore *)lc;
|
||||
LinphoneCall *call = (LinphoneCall *)c;
|
||||
int ret = linphone_core_accept_early_media(core, call);
|
||||
return (jboolean) ret == 0;
|
||||
}
|
||||
|
||||
extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_acceptEarlyMediaWithParams(JNIEnv *env, jobject thiz, jlong lc, jlong c, jlong params) {
|
||||
LinphoneCore *core = (LinphoneCore *)lc;
|
||||
LinphoneCall *call = (LinphoneCall *)c;
|
||||
const LinphoneCallParams *call_params = (LinphoneCallParams *) params;
|
||||
int ret = linphone_core_accept_early_media_with_params(core, call, call_params);
|
||||
return (jboolean) ret == 0;
|
||||
}
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getCallLog( JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc
|
||||
|
|
@ -983,6 +1070,20 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getNumberOfCallLogs( JNI
|
|||
,jlong lc) {
|
||||
return (jint)ms_list_size(linphone_core_get_call_logs((LinphoneCore*)lc));
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMtu(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc
|
||||
,jint mtu) {
|
||||
linphone_core_set_mtu((LinphoneCore*)lc,mtu);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMtu(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc) {
|
||||
return linphone_core_get_mtu((LinphoneCore*)lc);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setNetworkStateReachable( JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc
|
||||
|
|
@ -1276,6 +1377,25 @@ extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getRing(JNIEnv* env
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setTone(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc
|
||||
,jint toneid
|
||||
,jstring jpath) {
|
||||
const char* path = jpath ? env->GetStringUTFChars(jpath, NULL) : NULL;
|
||||
linphone_core_set_tone((LinphoneCore *)lc, (LinphoneToneID)toneid, path);
|
||||
if (path) env->ReleaseStringUTFChars(jpath, path);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setCallErrorTone(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc
|
||||
,jint reason
|
||||
,jstring jpath) {
|
||||
const char* path = jpath ? env->GetStringUTFChars(jpath, NULL) : NULL;
|
||||
linphone_core_set_call_error_tone((LinphoneCore *)lc, (LinphoneReason)reason, path);
|
||||
if (path) env->ReleaseStringUTFChars(jpath, path);
|
||||
}
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setRootCA(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc
|
||||
|
|
@ -1359,6 +1479,39 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMediaEncryptionMandat
|
|||
linphone_core_set_media_encryption_mandatory((LinphoneCore*)lc, yesno);
|
||||
}
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createProxyConfig(JNIEnv* env, jobject thiz, jlong lc) {
|
||||
LinphoneProxyConfig* proxy = linphone_core_create_proxy_config((LinphoneCore *)lc);
|
||||
return (jlong) proxy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_LinphoneCoreImpl
|
||||
* Method: disableChat
|
||||
* Signature: (JI)V
|
||||
*/
|
||||
extern "C" JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_disableChat(JNIEnv *env, jobject jobj, jlong ptr, jint reason){
|
||||
linphone_core_disable_chat((LinphoneCore*)ptr,(LinphoneReason)reason);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_LinphoneCoreImpl
|
||||
* Method: enableChat
|
||||
* Signature: (J)V
|
||||
*/
|
||||
extern "C" JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableChat(JNIEnv *env, jobject jobj, jlong ptr){
|
||||
linphone_core_enable_chat((LinphoneCore*)ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_LinphoneCoreImpl
|
||||
* Method: chatEnabled
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
extern "C" JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_chatEnabled(JNIEnv *env, jobject jobj, jlong ptr){
|
||||
return (jboolean) linphone_core_chat_enabled((LinphoneCore*)ptr);
|
||||
}
|
||||
|
||||
|
||||
//ProxyConfig
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_newLinphoneProxyConfig(JNIEnv* env,jobject thiz) {
|
||||
|
|
@ -1397,10 +1550,25 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getProxy(JNIEn
|
|||
}
|
||||
}
|
||||
extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setContactParameters(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jparams) {
|
||||
const char* params = env->GetStringUTFChars(jparams, NULL);
|
||||
const char* params = jparams ? env->GetStringUTFChars(jparams, NULL) : NULL;
|
||||
linphone_proxy_config_set_contact_parameters((LinphoneProxyConfig*)proxyCfg, params);
|
||||
env->ReleaseStringUTFChars(jparams, params);
|
||||
if (jparams) env->ReleaseStringUTFChars(jparams, params);
|
||||
}
|
||||
extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setContactUriParameters(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jparams) {
|
||||
const char* params = jparams ? env->GetStringUTFChars(jparams, NULL) : NULL;
|
||||
linphone_proxy_config_set_contact_uri_parameters((LinphoneProxyConfig*)proxyCfg, params);
|
||||
if (jparams) env->ReleaseStringUTFChars(jparams, params);
|
||||
}
|
||||
extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getContactParameters(JNIEnv* env,jobject thiz,jlong proxyCfg) {
|
||||
const char* params = linphone_proxy_config_get_contact_parameters((LinphoneProxyConfig*)proxyCfg);
|
||||
return params ? env->NewStringUTF(params) : NULL;
|
||||
}
|
||||
extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getContactUriParameters(JNIEnv* env,jobject thiz,jlong proxyCfg) {
|
||||
const char* params = linphone_proxy_config_get_contact_uri_parameters((LinphoneProxyConfig*)proxyCfg);
|
||||
return params ? env->NewStringUTF(params) : NULL;
|
||||
}
|
||||
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_setRoute(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jroute) {
|
||||
if (jroute != NULL) {
|
||||
const char* route = env->GetStringUTFChars(jroute, NULL);
|
||||
|
|
@ -1435,6 +1603,7 @@ extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_edit(JNIEnv* env,
|
|||
extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_done(JNIEnv* env,jobject thiz,jlong proxyCfg) {
|
||||
linphone_proxy_config_done((LinphoneProxyConfig*)proxyCfg);
|
||||
}
|
||||
|
||||
extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_normalizePhoneNumber(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jnumber) {
|
||||
if (jnumber == 0) {
|
||||
ms_error("cannot normalized null number");
|
||||
|
|
@ -1510,6 +1679,10 @@ extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getError(JNIEnv*
|
|||
return linphone_proxy_config_get_error((LinphoneProxyConfig *) ptr);
|
||||
}
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneProxyConfigImpl_getErrorInfo(JNIEnv* env,jobject thiz,jlong ptr) {
|
||||
return (jlong)linphone_proxy_config_get_error_info((LinphoneProxyConfig *) ptr);
|
||||
}
|
||||
|
||||
//Auth Info
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneAuthInfoImpl_newLinphoneAuthInfo(JNIEnv* env
|
||||
|
|
@ -1751,6 +1924,12 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv*
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
extern "C" jint Java_org_linphone_core_LinphoneAddressImpl_getTransport(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
LinphoneTransportType transporttype = linphone_address_get_transport((LinphoneAddress*)ptr);
|
||||
return (jint)transporttype;
|
||||
}
|
||||
extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toString(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
|
|
@ -1791,7 +1970,12 @@ extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDomain(JNIEnv* en
|
|||
linphone_address_set_domain((LinphoneAddress*)address,domain);
|
||||
if (domain != NULL) env->ReleaseStringUTFChars(jdomain, domain);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setTransport(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong address
|
||||
,jint jtransport) {
|
||||
linphone_address_set_transport((LinphoneAddress*)address, (LinphoneTransportType) jtransport);
|
||||
}
|
||||
|
||||
//CallLog
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneCallLogImpl_getFrom(JNIEnv* env
|
||||
|
|
@ -1846,95 +2030,21 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getUploadBandwidt
|
|||
}
|
||||
extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getSenderLossRate(JNIEnv *env, jobject thiz, jlong stats_ptr) {
|
||||
const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
|
||||
const report_block_t *srb = NULL;
|
||||
|
||||
if (!stats || !stats->sent_rtcp)
|
||||
return (jfloat)0.0;
|
||||
/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
|
||||
if (stats->sent_rtcp->b_cont != NULL)
|
||||
msgpullup(stats->sent_rtcp, -1);
|
||||
if (rtcp_is_SR(stats->sent_rtcp))
|
||||
srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
|
||||
else if (rtcp_is_RR(stats->sent_rtcp))
|
||||
srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
|
||||
if (!srb)
|
||||
return (jfloat)0.0;
|
||||
return (jfloat)(100.0 * report_block_get_fraction_lost(srb) / 256.0);
|
||||
return (jfloat) linphone_call_stats_get_sender_loss_rate(stats);
|
||||
}
|
||||
extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverLossRate(JNIEnv *env, jobject thiz, jlong stats_ptr) {
|
||||
const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
|
||||
const report_block_t *rrb = NULL;
|
||||
|
||||
if (!stats || !stats->received_rtcp)
|
||||
return (jfloat)0.0;
|
||||
/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
|
||||
if (stats->received_rtcp->b_cont != NULL)
|
||||
msgpullup(stats->received_rtcp, -1);
|
||||
if (rtcp_is_RR(stats->received_rtcp))
|
||||
rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
|
||||
else if (rtcp_is_SR(stats->received_rtcp))
|
||||
rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
|
||||
if (!rrb)
|
||||
return (jfloat)0.0;
|
||||
return (jfloat)(100.0 * report_block_get_fraction_lost(rrb) / 256.0);
|
||||
return (jfloat) linphone_call_stats_get_receiver_loss_rate(stats);
|
||||
}
|
||||
extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getSenderInterarrivalJitter(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) {
|
||||
LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
|
||||
LinphoneCall *call = (LinphoneCall *)call_ptr;
|
||||
const LinphoneCallParams *params;
|
||||
const PayloadType *pt;
|
||||
const report_block_t *srb = NULL;
|
||||
|
||||
if (!stats || !call || !stats->sent_rtcp)
|
||||
return (jfloat)0.0;
|
||||
params = linphone_call_get_current_params(call);
|
||||
if (!params)
|
||||
return (jfloat)0.0;
|
||||
/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
|
||||
if (stats->sent_rtcp->b_cont != NULL)
|
||||
msgpullup(stats->sent_rtcp, -1);
|
||||
if (rtcp_is_SR(stats->sent_rtcp))
|
||||
srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
|
||||
else if (rtcp_is_RR(stats->sent_rtcp))
|
||||
srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
|
||||
if (!srb)
|
||||
return (jfloat)0.0;
|
||||
if (stats->type == LINPHONE_CALL_STATS_AUDIO)
|
||||
pt = linphone_call_params_get_used_audio_codec(params);
|
||||
else
|
||||
pt = linphone_call_params_get_used_video_codec(params);
|
||||
if (!pt || (pt->clock_rate == 0))
|
||||
return (jfloat)0.0;
|
||||
return (jfloat)((float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate);
|
||||
return (jfloat) linphone_call_stats_get_sender_interarrival_jitter(stats, call);
|
||||
}
|
||||
extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverInterarrivalJitter(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) {
|
||||
LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
|
||||
LinphoneCall *call = (LinphoneCall *)call_ptr;
|
||||
const LinphoneCallParams *params;
|
||||
const PayloadType *pt;
|
||||
const report_block_t *rrb = NULL;
|
||||
|
||||
if (!stats || !call || !stats->received_rtcp)
|
||||
return (jfloat)0.0;
|
||||
params = linphone_call_get_current_params(call);
|
||||
if (!params)
|
||||
return (jfloat)0.0;
|
||||
/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
|
||||
if (stats->received_rtcp->b_cont != NULL)
|
||||
msgpullup(stats->received_rtcp, -1);
|
||||
if (rtcp_is_SR(stats->received_rtcp))
|
||||
rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
|
||||
else if (rtcp_is_RR(stats->received_rtcp))
|
||||
rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
|
||||
if (!rrb)
|
||||
return (jfloat)0.0;
|
||||
if (stats->type == LINPHONE_CALL_STATS_AUDIO)
|
||||
pt = linphone_call_params_get_used_audio_codec(params);
|
||||
else
|
||||
pt = linphone_call_params_get_used_video_codec(params);
|
||||
if (!pt || (pt->clock_rate == 0))
|
||||
return (jfloat)0.0;
|
||||
return (jfloat)((float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate);
|
||||
return (jfloat) linphone_call_stats_get_receiver_interarrival_jitter(stats, call);
|
||||
}
|
||||
extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getRoundTripDelay(JNIEnv *env, jobject thiz, jlong stats_ptr) {
|
||||
return (jfloat)((LinphoneCallStats *)stats_ptr)->round_trip_delay;
|
||||
|
|
@ -1942,18 +2052,7 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getRoundTripDelay
|
|||
extern "C" jlong Java_org_linphone_core_LinphoneCallStatsImpl_getLatePacketsCumulativeNumber(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) {
|
||||
LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
|
||||
LinphoneCall *call = (LinphoneCall *)call_ptr;
|
||||
rtp_stats_t rtp_stats;
|
||||
|
||||
if (!stats || !call)
|
||||
return (jlong)0;
|
||||
memset(&rtp_stats, 0, sizeof(rtp_stats));
|
||||
if (stats->type == LINPHONE_CALL_STATS_AUDIO)
|
||||
audio_stream_get_local_rtp_stats(call->audiostream, &rtp_stats);
|
||||
#ifdef VIDEO_ENABLED
|
||||
else
|
||||
video_stream_get_local_rtp_stats(call->videostream, &rtp_stats);
|
||||
#endif
|
||||
return (jlong)rtp_stats.outoftime;
|
||||
return (jlong) linphone_call_stats_get_late_packets_cumulative_number(stats, call);
|
||||
}
|
||||
extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getJitterBufferSize(JNIEnv *env, jobject thiz, jlong stats_ptr) {
|
||||
return (jfloat)((LinphoneCallStats *)stats_ptr)->jitter_stats.jitter_buffer_size_ms;
|
||||
|
|
@ -2036,6 +2135,18 @@ extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getRemoteAddress( JNIEn
|
|||
return (jlong)linphone_call_get_remote_address((LinphoneCall*)ptr);
|
||||
}
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getErrorInfo( JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
return (jlong)linphone_call_get_error_info((LinphoneCall*)ptr);
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getReason( JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
return (jint)linphone_call_get_reason((LinphoneCall*)ptr);
|
||||
}
|
||||
|
||||
extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getRemoteUserAgent(JNIEnv *env, jobject thiz, jlong ptr) {
|
||||
LinphoneCall *call = (LinphoneCall *)ptr;
|
||||
const char *value=linphone_call_get_remote_user_agent(call);
|
||||
|
|
@ -2190,6 +2301,16 @@ extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv* env
|
|||
,jlong ptr) {
|
||||
return (jint)linphone_friend_get_status((LinphoneFriend*)ptr);
|
||||
}
|
||||
extern "C" jobject Java_org_linphone_core_LinphoneFriendImpl_getCore(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
LinphoneCore *lc=linphone_friend_get_core((LinphoneFriend*)ptr);
|
||||
if (lc!=NULL){
|
||||
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
|
||||
return lcData->core;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_LinphoneFriendImpl
|
||||
|
|
@ -2295,6 +2416,12 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteHistory(JNIEnv
|
|||
,jlong ptr) {
|
||||
linphone_chat_room_delete_history((LinphoneChatRoom*)ptr);
|
||||
}
|
||||
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneChatRoomImpl_compose(JNIEnv *env, jobject thiz, jlong ptr) {
|
||||
linphone_chat_room_compose((LinphoneChatRoom *)ptr);
|
||||
}
|
||||
JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneChatRoomImpl_isRemoteComposing(JNIEnv *env, jobject thiz, jlong ptr) {
|
||||
return (jboolean)linphone_chat_room_is_remote_composing((LinphoneChatRoom *)ptr);
|
||||
}
|
||||
extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteMessage(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong room
|
||||
|
|
@ -2320,13 +2447,6 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_destroy(JNIEnv* env
|
|||
linphone_chat_room_destroy((LinphoneChatRoom*)ptr);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setUserData(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
jobject ud = env->NewGlobalRef(thiz);
|
||||
linphone_chat_message_set_user_data((LinphoneChatMessage*)ptr,(void*) ud);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_store(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
|
|
@ -2340,6 +2460,18 @@ extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNIEnv
|
|||
return jvalue;
|
||||
}
|
||||
|
||||
extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getReason(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
return linphone_chat_message_get_reason((LinphoneChatMessage*)ptr);
|
||||
}
|
||||
|
||||
extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getErrorInfo(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
return (jlong)linphone_chat_message_get_error_info((LinphoneChatMessage*)ptr);
|
||||
}
|
||||
|
||||
extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getCustomHeader(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr, jstring jheader_name) {
|
||||
|
|
@ -2415,6 +2547,12 @@ extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getStorageId(JNIE
|
|||
return (jint) linphone_chat_message_get_storage_id((LinphoneChatMessage*)ptr);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_unref(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
linphone_chat_message_unref((LinphoneChatMessage*)ptr);
|
||||
}
|
||||
|
||||
extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getChatRooms(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr) {
|
||||
|
|
@ -2453,26 +2591,32 @@ static void chat_room_impl_callback(LinphoneChatMessage* msg, LinphoneChatMessag
|
|||
jobject listener = (jobject) ud;
|
||||
jclass clazz = (jclass) env->GetObjectClass(listener);
|
||||
jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageStateChanged","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneChatMessage$State;)V");
|
||||
|
||||
jobject jmessage=(jobject)linphone_chat_message_get_user_data(msg);
|
||||
LinphoneCore *lc = linphone_chat_room_get_lc(linphone_chat_message_get_chat_room(msg));
|
||||
LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
|
||||
env->CallVoidMethod(
|
||||
listener,
|
||||
method,
|
||||
(jobject)linphone_chat_message_get_user_data(msg),
|
||||
jmessage,
|
||||
env->CallStaticObjectMethod(lcData->chatMessageStateClass,lcData->chatMessageStateFromIntId,(jint)state));
|
||||
|
||||
|
||||
if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) {
|
||||
env->DeleteGlobalRef(listener);
|
||||
env->DeleteGlobalRef(jmessage);
|
||||
linphone_chat_message_set_user_data(msg,NULL);
|
||||
}
|
||||
}
|
||||
extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong ptr
|
||||
,jlong jmessage
|
||||
,jlong chatroom_ptr
|
||||
,jobject message
|
||||
,jlong messagePtr
|
||||
,jobject jlistener) {
|
||||
jobject listener = env->NewGlobalRef(jlistener);
|
||||
linphone_chat_room_send_message2((LinphoneChatRoom*)ptr, (LinphoneChatMessage*)jmessage, chat_room_impl_callback, (void*)listener);
|
||||
message = env->NewGlobalRef(message);
|
||||
linphone_chat_message_ref((LinphoneChatMessage*)messagePtr);
|
||||
linphone_chat_message_set_user_data((LinphoneChatMessage*)messagePtr, message);
|
||||
linphone_chat_room_send_message2((LinphoneChatRoom*)chatroom_ptr, (LinphoneChatMessage*)messagePtr, chat_room_impl_callback, (void*)listener);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env
|
||||
|
|
@ -2582,6 +2726,23 @@ extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setPrivacy(JNIEnv*
|
|||
linphone_call_params_set_privacy((LinphoneCallParams*)cp,privacy);
|
||||
}
|
||||
|
||||
extern "C" jstring Java_org_linphone_core_LinphoneCallParamsImpl_getSessionName(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong cp
|
||||
) {
|
||||
const char* name = linphone_call_params_get_session_name((LinphoneCallParams*)cp);
|
||||
return name ? env->NewStringUTF(name) : NULL;
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setSessionName(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong cp
|
||||
,jstring jname) {
|
||||
const char *name = jname ? env->GetStringUTFChars(jname,NULL) : NULL;
|
||||
linphone_call_params_set_session_name((LinphoneCallParams*)cp,name);
|
||||
if (name) env->ReleaseStringUTFChars(jname,name);
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_audioBandwidth(JNIEnv *env, jobject thiz, jlong lcp, jint bw){
|
||||
linphone_call_params_set_audio_bandwidth_limit((LinphoneCallParams*)lcp, bw);
|
||||
}
|
||||
|
|
@ -2621,6 +2782,24 @@ extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setRecordFile(JNIE
|
|||
}else linphone_call_params_set_record_file((LinphoneCallParams*)lcp,NULL);
|
||||
}
|
||||
|
||||
extern "C" jintArray Java_org_linphone_core_LinphoneCallParamsImpl_getSentVideoSize(JNIEnv *env, jobject thiz, jlong lcp) {
|
||||
const LinphoneCallParams *params = (LinphoneCallParams *) lcp;
|
||||
MSVideoSize vsize = linphone_call_params_get_sent_video_size(params);
|
||||
jintArray arr = env->NewIntArray(2);
|
||||
int tVsize [2]= {vsize.width,vsize.height};
|
||||
env->SetIntArrayRegion(arr, 0, 2, tVsize);
|
||||
return arr;
|
||||
}
|
||||
|
||||
extern "C" jintArray Java_org_linphone_core_LinphoneCallParamsImpl_getReceivedVideoSize(JNIEnv *env, jobject thiz, jlong lcp) {
|
||||
const LinphoneCallParams *params = (LinphoneCallParams *) lcp;
|
||||
MSVideoSize vsize = linphone_call_params_get_received_video_size(params);
|
||||
jintArray arr = env->NewIntArray(2);
|
||||
int tVsize [2]= {vsize.width,vsize.height};
|
||||
env->SetIntArrayRegion(arr, 0, 2, tVsize);
|
||||
return arr;
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_destroy(JNIEnv *env, jobject thiz, jlong lc){
|
||||
return linphone_call_params_destroy((LinphoneCallParams*)lc);
|
||||
}
|
||||
|
|
@ -2866,6 +3045,11 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_transferCallToAnother(JN
|
|||
return (jint)linphone_core_transfer_call_to_another((LinphoneCore *) pCore, (LinphoneCall *) pCall, (LinphoneCall *) pDestCall);
|
||||
}
|
||||
|
||||
extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_startReferedCall(JNIEnv *env, jobject thiz, jlong lc, jlong callptr, jlong params){
|
||||
LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc);
|
||||
return lcd->getCall(env,linphone_core_start_refered_call((LinphoneCore *)lc, (LinphoneCall *)callptr, (const LinphoneCallParams *)params));
|
||||
}
|
||||
|
||||
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setZrtpSecretsCache(JNIEnv *env,jobject thiz,jlong pCore, jstring jFile) {
|
||||
if (jFile) {
|
||||
const char* cFile=env->GetStringUTFChars(jFile, NULL);
|
||||
|
|
@ -2926,6 +3110,26 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getVideoDevice(JNIEnv *e
|
|||
return 0;
|
||||
}
|
||||
|
||||
extern "C" jobjectArray Java_org_linphone_core_LinphoneCoreImpl_listSupportedVideoResolutions(JNIEnv *env, jobject thiz, jlong lc) {
|
||||
const MSVideoSizeDef *pdef = linphone_core_get_supported_video_sizes((LinphoneCore *)lc);
|
||||
int count = 0;
|
||||
int i = 0;
|
||||
for (; pdef->name!=NULL; pdef++) {
|
||||
i++;
|
||||
}
|
||||
count = i;
|
||||
|
||||
jobjectArray resolutions = (jobjectArray) env->NewObjectArray(count, env->FindClass("java/lang/String"), env->NewStringUTF(""));
|
||||
pdef = linphone_core_get_supported_video_sizes((LinphoneCore *)lc);
|
||||
i = 0;
|
||||
for (; pdef->name!=NULL; pdef++) {
|
||||
env->SetObjectArrayElement(resolutions, i, env->NewStringUTF(pdef->name));
|
||||
i++;
|
||||
}
|
||||
|
||||
return resolutions;
|
||||
}
|
||||
|
||||
extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getAuthenticationToken(JNIEnv* env,jobject thiz,jlong ptr) {
|
||||
LinphoneCall *call = (LinphoneCall *) ptr;
|
||||
const char* token = linphone_call_get_authentication_token(call);
|
||||
|
|
@ -3124,7 +3328,7 @@ extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getUpnpExternalIpaddr
|
|||
* Signature: (JJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_subscribe(JNIEnv *env, jobject jcore, jlong coreptr, jlong addrptr,
|
||||
jstring jevname, jint expires, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){
|
||||
jstring jevname, jint expires, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){
|
||||
LinphoneCore *lc=(LinphoneCore*)coreptr;
|
||||
LinphoneAddress *addr=(LinphoneAddress*)addrptr;
|
||||
LinphoneContent content={0};
|
||||
|
|
@ -3136,7 +3340,7 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_subscribe(JNIE
|
|||
if (jtype){
|
||||
content.type=(char*)env->GetStringUTFChars(jtype,NULL);
|
||||
content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL);
|
||||
content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL;
|
||||
content.encoding=jencoding ? (char*)env->GetStringUTFChars(jencoding,NULL) : NULL;
|
||||
content.data=(void*)env->GetByteArrayElements(jdata,NULL);
|
||||
content.size=env->GetArrayLength(jdata);
|
||||
}
|
||||
|
|
@ -3172,7 +3376,7 @@ JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_publish(JNIEnv
|
|||
if (jtype){
|
||||
content.type=(char*)env->GetStringUTFChars(jtype,NULL);
|
||||
content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL);
|
||||
content.encoding=jencoding ? (char*)env->GetStringUTFChars(jsubtype,NULL) : NULL;
|
||||
content.encoding=jencoding ? (char*)env->GetStringUTFChars(jencoding,NULL) : NULL;
|
||||
content.data=(void*)env->GetByteArrayElements(jdata,NULL);
|
||||
content.size=env->GetArrayLength(jdata);
|
||||
}
|
||||
|
|
@ -3269,11 +3473,11 @@ extern "C" void Java_org_linphone_core_LpConfigImpl_setString(JNIEnv *env, jobje
|
|||
jstring section, jstring key, jstring value) {
|
||||
const char *csection = env->GetStringUTFChars(section, NULL);
|
||||
const char *ckey = env->GetStringUTFChars(key, NULL);
|
||||
const char *cvalue = env->GetStringUTFChars(value, NULL);
|
||||
const char *cvalue = value ? env->GetStringUTFChars(value, NULL) : NULL;
|
||||
lp_config_set_string((LpConfig *)lpc, csection, ckey, cvalue);
|
||||
env->ReleaseStringUTFChars(section, csection);
|
||||
env->ReleaseStringUTFChars(key, ckey);
|
||||
env->ReleaseStringUTFChars(value, cvalue);
|
||||
if (value) env->ReleaseStringUTFChars(value, cvalue);
|
||||
}
|
||||
|
||||
extern "C" jstring Java_org_linphone_core_LpConfigImpl_getString(JNIEnv *env, jobject thiz, jlong lpc,
|
||||
|
|
@ -3564,6 +3768,11 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getReason(JNIEnv
|
|||
return linphone_event_get_reason(ev);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_org_linphone_core_LinphoneEventImpl_getErrorInfo(JNIEnv *env, jobject jobj, jlong evptr){
|
||||
LinphoneEvent *ev=(LinphoneEvent*)evptr;
|
||||
return (jlong)linphone_event_get_error_info(ev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_LinphoneEventImpl
|
||||
* Method: getSubscriptionDir
|
||||
|
|
@ -3584,6 +3793,90 @@ JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getSubscriptionS
|
|||
return linphone_event_get_subscription_state(ev);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_createSubscribe(JNIEnv *env, jobject thiz, jlong jcore, jlong jaddr, jstring jeventname, jint expires) {
|
||||
LinphoneCore *lc = (LinphoneCore*) jcore;
|
||||
LinphoneCoreData* lcData = (LinphoneCoreData*) linphone_core_get_user_data(lc);
|
||||
LinphoneAddress *addr = (LinphoneAddress*) jaddr;
|
||||
LinphoneEvent *event;
|
||||
jobject jevent = NULL;
|
||||
const char *event_name = env->GetStringUTFChars(jeventname, NULL);
|
||||
|
||||
event = linphone_core_create_subscribe(lc, addr, event_name, expires);
|
||||
env->ReleaseStringUTFChars(jeventname, event_name);
|
||||
if (event) {
|
||||
jevent = lcData->getEvent(env, event);
|
||||
}
|
||||
return jevent;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_sendSubscribe(JNIEnv *env, jobject thiz, jlong jevent, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding) {
|
||||
LinphoneContent content = {0};
|
||||
if (jtype) {
|
||||
content.type = (char*) env->GetStringUTFChars(jtype, NULL);
|
||||
content.subtype = (char*) env->GetStringUTFChars(jsubtype, NULL);
|
||||
content.encoding = jencoding ? (char*) env->GetStringUTFChars(jencoding, NULL) : NULL;
|
||||
content.data = (void*) env->GetByteArrayElements(jdata, NULL);
|
||||
content.size = env->GetArrayLength(jdata);
|
||||
}
|
||||
linphone_event_send_subscribe((LinphoneEvent*) jevent, content.type ? &content : NULL);
|
||||
if (jtype) {
|
||||
env->ReleaseStringUTFChars(jtype, content.type);
|
||||
env->ReleaseStringUTFChars(jsubtype, content.subtype);
|
||||
if (jencoding) env->ReleaseStringUTFChars(jencoding, content.encoding);
|
||||
env->ReleaseByteArrayElements(jdata, (jbyte*) content.data, JNI_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_createPublish(JNIEnv *env, jobject thiz, jlong jcore, jlong jaddr, jstring jeventname, jint expires) {
|
||||
LinphoneCore *lc = (LinphoneCore*) jcore;
|
||||
LinphoneCoreData* lcData = (LinphoneCoreData*) linphone_core_get_user_data(lc);
|
||||
LinphoneAddress *addr = (LinphoneAddress*) jaddr;
|
||||
LinphoneEvent *event;
|
||||
jobject jevent = NULL;
|
||||
const char *event_name = env->GetStringUTFChars(jeventname, NULL);
|
||||
|
||||
event = linphone_core_create_publish(lc, addr, event_name, expires);
|
||||
env->ReleaseStringUTFChars(jeventname, event_name);
|
||||
if (event) {
|
||||
jevent = lcData->getEvent(env, event);
|
||||
}
|
||||
return jevent;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_sendPublish(JNIEnv *env, jobject thiz, jlong jevent, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding) {
|
||||
LinphoneContent content = {0};
|
||||
if (jtype) {
|
||||
content.type = (char*) env->GetStringUTFChars(jtype, NULL);
|
||||
content.subtype = (char*) env->GetStringUTFChars(jsubtype, NULL);
|
||||
content.encoding = jencoding ? (char*) env->GetStringUTFChars(jencoding, NULL) : NULL;
|
||||
content.data = (void*) env->GetByteArrayElements(jdata, NULL);
|
||||
content.size = env->GetArrayLength(jdata);
|
||||
}
|
||||
linphone_event_send_publish((LinphoneEvent*) jevent, content.type ? &content : NULL);
|
||||
if (jtype) {
|
||||
env->ReleaseStringUTFChars(jtype, content.type);
|
||||
env->ReleaseStringUTFChars(jsubtype, content.subtype);
|
||||
if (jencoding) env->ReleaseStringUTFChars(jencoding, content.encoding);
|
||||
env->ReleaseByteArrayElements(jdata, (jbyte*) content.data, JNI_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_addCustomHeader(JNIEnv *env, jobject thiz, jlong jevent, jstring jname, jstring jvalue) {
|
||||
const char *name = jname ? env->GetStringUTFChars(jname, NULL) : NULL;
|
||||
const char *value = jvalue ? env->GetStringUTFChars(jvalue, NULL) : NULL;
|
||||
linphone_event_add_custom_header((LinphoneEvent*) jevent, name, value);
|
||||
if (jname) env->ReleaseStringUTFChars(jname, name);
|
||||
if (jvalue) env->ReleaseStringUTFChars(jvalue, value);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneEventImpl_getCustomHeader(JNIEnv *env, jobject thiz, jlong jevent, jstring jname) {
|
||||
const char *name = jname ? env->GetStringUTFChars(jname, NULL) : NULL;
|
||||
const char *header = linphone_event_get_custom_header((LinphoneEvent*) jevent, name);
|
||||
jstring jheader = header ? env->NewStringUTF(header) : NULL;
|
||||
if (jname) env->ReleaseStringUTFChars(jname, name);
|
||||
return jheader;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_LinphoneEventImpl
|
||||
* Method: unref
|
||||
|
|
@ -3600,7 +3893,9 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_unref(JNIEnv *en
|
|||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceModelImpl__(JNIEnv *env, jobject jobj) {
|
||||
return (jlong)linphone_presence_model_new();
|
||||
LinphonePresenceModel *model = linphone_presence_model_new();
|
||||
model = linphone_presence_model_ref(model);
|
||||
return (jlong)model;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3612,6 +3907,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceMode
|
|||
LinphonePresenceModel *model;
|
||||
const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL;
|
||||
model = linphone_presence_model_new_with_activity((LinphonePresenceActivityType)type, cdescription);
|
||||
model = linphone_presence_model_ref(model);
|
||||
if (cdescription) env->ReleaseStringUTFChars(description, cdescription);
|
||||
return (jlong)model;
|
||||
}
|
||||
|
|
@ -3628,6 +3924,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceMode
|
|||
const char *cnote = note ? env->GetStringUTFChars(note, NULL) : NULL;
|
||||
const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL;
|
||||
model = linphone_presence_model_new_with_activity_and_note((LinphonePresenceActivityType)type, cdescription, cnote, clang);
|
||||
model = linphone_presence_model_ref(model);
|
||||
if (cdescription) env->ReleaseStringUTFChars(description, cdescription);
|
||||
if (cnote) env->ReleaseStringUTFChars(note, cnote);
|
||||
if (clang) env->ReleaseStringUTFChars(lang, clang);
|
||||
|
|
@ -3896,6 +4193,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceActivityImpl_newPresenceA
|
|||
LinphonePresenceActivity *activity;
|
||||
const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL;
|
||||
activity = linphone_presence_activity_new((LinphonePresenceActivityType)type, cdescription);
|
||||
activity = linphone_presence_activity_ref(activity);
|
||||
if (cdescription) env->ReleaseStringUTFChars(description, cdescription);
|
||||
return (jlong)activity;
|
||||
}
|
||||
|
|
@ -3976,6 +4274,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_newPresenceSe
|
|||
const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL;
|
||||
const char *ccontact = contact ? env->GetStringUTFChars(contact, NULL) : NULL;
|
||||
service = linphone_presence_service_new(cid, (LinphonePresenceBasicStatus)basic_status, ccontact);
|
||||
service = linphone_presence_service_ref(service);
|
||||
if (cid) env->ReleaseStringUTFChars(id, cid);
|
||||
if (ccontact) env->ReleaseStringUTFChars(contact, ccontact);
|
||||
return (jlong)service;
|
||||
|
|
@ -4111,6 +4410,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_newPresencePer
|
|||
LinphonePresencePerson *person;
|
||||
const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL;
|
||||
person = linphone_presence_person_new(cid);
|
||||
person = linphone_presence_person_ref(person);
|
||||
if (cid) env->ReleaseStringUTFChars(id, cid);
|
||||
return (jlong)person;
|
||||
}
|
||||
|
|
@ -4283,6 +4583,7 @@ JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceNoteImpl_newPresenceNoteI
|
|||
const char *ccontent = content ? env->GetStringUTFChars(content, NULL) : NULL;
|
||||
const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL;
|
||||
note = linphone_presence_note_new(ccontent, clang);
|
||||
note = linphone_presence_note_ref(note);
|
||||
if (clang) env->ReleaseStringUTFChars(lang, clang);
|
||||
if (ccontent) env->ReleaseStringUTFChars(content, ccontent);
|
||||
return (jlong)note;
|
||||
|
|
@ -4391,6 +4692,62 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_PayloadTypeImpl_getSendFmtp(JNI
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_enableSdp200Ack(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc
|
||||
,jboolean enable) {
|
||||
linphone_core_enable_sdp_200_ack((LinphoneCore*)lc,enable);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneCoreImpl_isSdp200AckEnabled(JNIEnv* env
|
||||
,jobject thiz
|
||||
,jlong lc) {
|
||||
return (jboolean)linphone_core_sdp_200_ack_enabled((const LinphoneCore*)lc);
|
||||
}
|
||||
|
||||
/* Header for class org_linphone_core_ErrorInfoImpl */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: org_linphone_core_ErrorInfoImpl
|
||||
* Method: getReason
|
||||
* Signature: (J)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_linphone_core_ErrorInfoImpl_getReason(JNIEnv *env, jobject jobj, jlong ei){
|
||||
return linphone_error_info_get_reason((const LinphoneErrorInfo*)ei);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_ErrorInfoImpl
|
||||
* Method: getProtocolCode
|
||||
* Signature: (J)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_linphone_core_ErrorInfoImpl_getProtocolCode(JNIEnv *env, jobject jobj, jlong ei){
|
||||
return linphone_error_info_get_protocol_code((const LinphoneErrorInfo*)ei);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_ErrorInfoImpl
|
||||
* Method: getPhrase
|
||||
* Signature: (J)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getPhrase(JNIEnv *env, jobject jobj, jlong ei){
|
||||
const char *tmp=linphone_error_info_get_phrase((const LinphoneErrorInfo*)ei);
|
||||
return tmp ? env->NewStringUTF(tmp) : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_linphone_core_ErrorInfoImpl
|
||||
* Method: getDetails
|
||||
* Signature: (J)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getDetails(JNIEnv *env, jobject jobj, jlong ei){
|
||||
const char *tmp=linphone_error_info_get_details((const LinphoneErrorInfo*)ei);
|
||||
return tmp ? env->NewStringUTF(tmp) : NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -392,6 +392,11 @@ LINPHONE_PUBLIC LinphoneFriend *linphone_core_find_friend(const LinphoneCore *lc
|
|||
*/
|
||||
LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the LinphoneCore object managing this friend, if any.
|
||||
*/
|
||||
LINPHONE_PUBLIC LinphoneCore *linphone_friend_get_core(const LinphoneFriend *fr);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -731,140 +731,140 @@ LINPHONE_PUBLIC int linphone_presence_note_set_lang(LinphonePresenceNote *note,
|
|||
* @param[in] model The #LinphonePresenceModel object for which the reference count is to be increased.
|
||||
* @return The #LinphonePresenceModel object with the increased reference count.
|
||||
*/
|
||||
LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model);
|
||||
LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model);
|
||||
|
||||
/**
|
||||
* Decrease the reference count of the #LinphonePresenceModel object and destroy it if it reaches 0.
|
||||
* @param[in] model The #LinphonePresenceModel object for which the reference count is to be decreased.
|
||||
* @return The #LinphonePresenceModel object if the reference count is still positive, NULL if the object has been destroyed.
|
||||
*/
|
||||
LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model);
|
||||
LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model);
|
||||
|
||||
/**
|
||||
* Sets the user data of a #LinphonePresenceModel object.
|
||||
* @param[in] model The #LinphonePresenceModel object for which to set the user data.
|
||||
* @param[in] user_data A pointer to the user data to set.
|
||||
*/
|
||||
void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data);
|
||||
LINPHONE_PUBLIC void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data);
|
||||
|
||||
/**
|
||||
* Gets the user data of a #LinphonePresenceModel object.
|
||||
* @param[in] model The #LinphonePresenceModel object for which to get the user data.
|
||||
* @return A pointer to the user data.
|
||||
*/
|
||||
void * linphone_presence_model_get_user_data(LinphonePresenceModel *model);
|
||||
LINPHONE_PUBLIC void * linphone_presence_model_get_user_data(LinphonePresenceModel *model);
|
||||
|
||||
/**
|
||||
* Increase the reference count of the #LinphonePresenceService object.
|
||||
* @param[in] service The #LinphonePresenceService object for which the reference count is to be increased.
|
||||
* @return The #LinphonePresenceService object with the increased reference count.
|
||||
*/
|
||||
LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service);
|
||||
LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service);
|
||||
|
||||
/**
|
||||
* Decrease the reference count of the #LinphonePresenceService object and destroy it if it reaches 0.
|
||||
* @param[in] service The #LinphonePresenceService object for which the reference count is to be decreased.
|
||||
* @return The #LinphonePresenceService object if the reference count is still positive, NULL if the object has been destroyed.
|
||||
*/
|
||||
LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service);
|
||||
LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service);
|
||||
|
||||
/**
|
||||
* Sets the user data of a #LinphonePresenceService object.
|
||||
* @param[in] service The #LinphonePresenceService object for which to set the user data.
|
||||
* @param[in] user_data A pointer to the user data to set.
|
||||
*/
|
||||
void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data);
|
||||
LINPHONE_PUBLIC void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data);
|
||||
|
||||
/**
|
||||
* Gets the user data of a #LinphonePresenceService object.
|
||||
* @param[in] service The #LinphonePresenceService object for which to get the user data.
|
||||
* @return A pointer to the user data.
|
||||
*/
|
||||
void * linphone_presence_service_get_user_data(LinphonePresenceService *service);
|
||||
LINPHONE_PUBLIC void * linphone_presence_service_get_user_data(LinphonePresenceService *service);
|
||||
|
||||
/**
|
||||
* Increase the reference count of the #LinphonePresencePerson object.
|
||||
* @param[in] person The #LinphonePresencePerson object for which the reference count is to be increased.
|
||||
* @return The #LinphonePresencePerson object with the increased reference count.
|
||||
*/
|
||||
LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person);
|
||||
LINPHONE_PUBLIC LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person);
|
||||
|
||||
/**
|
||||
* Decrease the reference count of the #LinphonePresencePerson object and destroy it if it reaches 0.
|
||||
* @param[in] person The #LinphonePresencePerson object for which the reference count is to be decreased.
|
||||
* @return The #LinphonePresencePerson object if the reference count is still positive, NULL if the object has been destroyed.
|
||||
*/
|
||||
LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person);
|
||||
LINPHONE_PUBLIC LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person);
|
||||
|
||||
/**
|
||||
* Sets the user data of a #LinphonePresencePerson object.
|
||||
* @param[in] person The #LinphonePresencePerson object for which to set the user data.
|
||||
* @param[in] user_data A pointer to the user data to set.
|
||||
*/
|
||||
void linphone_presence_person_set_user_data(LinphonePresencePerson *person, void *user_data);
|
||||
LINPHONE_PUBLIC void linphone_presence_person_set_user_data(LinphonePresencePerson *person, void *user_data);
|
||||
|
||||
/**
|
||||
* Gets the user data of a #LinphonePresencePerson object.
|
||||
* @param[in] person The #LinphonePresencePerson object for which to get the user data.
|
||||
* @return A pointer to the user data.
|
||||
*/
|
||||
void * linphone_presence_person_get_user_data(LinphonePresencePerson *person);
|
||||
LINPHONE_PUBLIC void * linphone_presence_person_get_user_data(LinphonePresencePerson *person);
|
||||
|
||||
/**
|
||||
* Increase the reference count of the #LinphonePresenceActivity object.
|
||||
* @param[in] activity The #LinphonePresenceActivity object for which the reference count is to be increased.
|
||||
* @return The #LinphonePresenceActivity object with the increased reference count.
|
||||
*/
|
||||
LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity);
|
||||
LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity);
|
||||
|
||||
/**
|
||||
* Decrease the reference count of the #LinphonePresenceActivity object and destroy it if it reaches 0.
|
||||
* @param[in] activity The #LinphonePresenceActivity object for which the reference count is to be decreased.
|
||||
* @return The #LinphonePresenceActivity object if the reference count is still positive, NULL if the object has been destroyed.
|
||||
*/
|
||||
LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity);
|
||||
LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity);
|
||||
|
||||
/**
|
||||
* Sets the user data of a #LinphonePresenceActivity object.
|
||||
* @param[in] activity The #LinphonePresenceActivity object for which to set the user data.
|
||||
* @param[in] user_data A pointer to the user data to set.
|
||||
*/
|
||||
void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data);
|
||||
LINPHONE_PUBLIC void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data);
|
||||
|
||||
/**
|
||||
* Gets the user data of a #LinphonePresenceActivity object.
|
||||
* @param[in] activity The #LinphonePresenceActivity object for which to get the user data.
|
||||
* @return A pointer to the user data.
|
||||
*/
|
||||
void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity);
|
||||
LINPHONE_PUBLIC void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity);
|
||||
|
||||
/**
|
||||
* Increase the reference count of the #LinphonePresenceNote object.
|
||||
* @param[in] note The #LinphonePresenceNote object for which the reference count is to be increased.
|
||||
* @return The #LinphonePresenceNote object with the increased reference count.
|
||||
*/
|
||||
LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note);
|
||||
LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note);
|
||||
|
||||
/**
|
||||
* Decrease the reference count of the #LinphonePresenceNote object and destroy it if it reaches 0.
|
||||
* @param[in] note The #LinphonePresenceNote object for which the reference count is to be decreased.
|
||||
* @return The #LinphonePresenceNote object if the reference count is still positive, NULL if the object has been destroyed.
|
||||
*/
|
||||
LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note);
|
||||
LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note);
|
||||
|
||||
/**
|
||||
* Sets the user data of a #LinphonePresenceNote object.
|
||||
* @param[in] note The #LinphonePresenceNote object for which to set the user data.
|
||||
* @param[in] user_data A pointer to the user data to set.
|
||||
*/
|
||||
void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data);
|
||||
LINPHONE_PUBLIC void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data);
|
||||
|
||||
/**
|
||||
* Gets the user data of a #LinphonePresenceNote object.
|
||||
* @param[in] note The #LinphonePresenceNote object for which to get the user data.
|
||||
* @return A pointer to the user data.
|
||||
*/
|
||||
void * linphone_presence_note_get_user_data(LinphonePresenceNote *note);
|
||||
LINPHONE_PUBLIC void * linphone_presence_note_get_user_data(LinphonePresenceNote *note);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
|
|||
|
|
@ -51,12 +51,19 @@ typedef struct _LpItem{
|
|||
char *value;
|
||||
} LpItem;
|
||||
|
||||
typedef struct _LpSectionParam{
|
||||
char *key;
|
||||
char *value;
|
||||
} LpSectionParam;
|
||||
|
||||
typedef struct _LpSection{
|
||||
char *name;
|
||||
MSList *items;
|
||||
MSList *params;
|
||||
} LpSection;
|
||||
|
||||
struct _LpConfig{
|
||||
int refcnt;
|
||||
FILE *file;
|
||||
char *filename;
|
||||
MSList *sections;
|
||||
|
|
@ -71,6 +78,13 @@ LpItem * lp_item_new(const char *key, const char *value){
|
|||
return item;
|
||||
}
|
||||
|
||||
LpSectionParam *lp_section_param_new(const char *key, const char *value){
|
||||
LpSectionParam *param = lp_new0(LpSectionParam, 1);
|
||||
param->key = ortp_strdup(key);
|
||||
param->value = ortp_strdup(value);
|
||||
return param;
|
||||
}
|
||||
|
||||
LpSection *lp_section_new(const char *name){
|
||||
LpSection *sec=lp_new0(LpSection,1);
|
||||
sec->name=ortp_strdup(name);
|
||||
|
|
@ -79,14 +93,22 @@ LpSection *lp_section_new(const char *name){
|
|||
|
||||
void lp_item_destroy(void *pitem){
|
||||
LpItem *item=(LpItem*)pitem;
|
||||
free(item->key);
|
||||
free(item->value);
|
||||
ortp_free(item->key);
|
||||
ortp_free(item->value);
|
||||
free(item);
|
||||
}
|
||||
|
||||
void lp_section_param_destroy(void *section_param){
|
||||
LpSectionParam *param = (LpSectionParam*)section_param;
|
||||
ortp_free(param->key);
|
||||
ortp_free(param->value);
|
||||
free(param);
|
||||
}
|
||||
|
||||
void lp_section_destroy(LpSection *sec){
|
||||
free(sec->name);
|
||||
ortp_free(sec->name);
|
||||
ms_list_for_each(sec->items,lp_item_destroy);
|
||||
ms_list_for_each(sec->params,lp_section_param_destroy);
|
||||
ms_list_free(sec->items);
|
||||
free(sec);
|
||||
}
|
||||
|
|
@ -99,6 +121,10 @@ void lp_config_add_section(LpConfig *lpconfig, LpSection *section){
|
|||
lpconfig->sections=ms_list_append(lpconfig->sections,(void *)section);
|
||||
}
|
||||
|
||||
void lp_config_add_section_param(LpSection *section, LpSectionParam *param){
|
||||
section->params = ms_list_append(section->params, (void *)param);
|
||||
}
|
||||
|
||||
void lp_config_remove_section(LpConfig *lpconfig, LpSection *section){
|
||||
lpconfig->sections=ms_list_remove(lpconfig->sections,(void *)section);
|
||||
lp_section_destroy(section);
|
||||
|
|
@ -126,6 +152,18 @@ LpSection *lp_config_find_section(const LpConfig *lpconfig, const char *name){
|
|||
return NULL;
|
||||
}
|
||||
|
||||
LpSectionParam *lp_section_find_param(const LpSection *sec, const char *key){
|
||||
MSList *elem;
|
||||
LpSectionParam *param;
|
||||
for (elem = sec->params; elem != NULL; elem = ms_list_next(elem)){
|
||||
param = (LpSectionParam*)elem->data;
|
||||
if (strcmp(param->key, key) == 0) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LpItem *lp_section_find_item(const LpSection *sec, const char *name){
|
||||
MSList *elem;
|
||||
LpItem *item;
|
||||
|
|
@ -140,77 +178,107 @@ LpItem *lp_section_find_item(const LpSection *sec, const char *name){
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void lp_config_parse(LpConfig *lpconfig, FILE *file){
|
||||
char tmp[MAX_LEN]= {'\0'};
|
||||
LpSection *cur=NULL;
|
||||
static LpSection* lp_config_parse_line(LpConfig* lpconfig, const char* line, LpSection* cur) {
|
||||
LpSectionParam *params = NULL;
|
||||
char *pos1,*pos2;
|
||||
int nbs;
|
||||
char secname[MAX_LEN];
|
||||
char key[MAX_LEN];
|
||||
static char secname[MAX_LEN];
|
||||
static char key[MAX_LEN];
|
||||
static char value[MAX_LEN];
|
||||
LpItem *item;
|
||||
|
||||
pos1=strchr(line,'[');
|
||||
if (pos1!=NULL && is_first_char(line,pos1) ){
|
||||
pos2=strchr(pos1,']');
|
||||
if (pos2!=NULL){
|
||||
secname[0]='\0';
|
||||
/* found section */
|
||||
*pos2='\0';
|
||||
nbs = sscanf(pos1+1, "%s", secname);
|
||||
if (nbs >= 1) {
|
||||
if (strlen(secname) > 0) {
|
||||
cur = lp_config_find_section (lpconfig,secname);
|
||||
if (cur == NULL) {
|
||||
cur = lp_section_new(secname);
|
||||
lp_config_add_section(lpconfig, cur);
|
||||
}
|
||||
|
||||
if (pos2 > pos1 + 1 + strlen(secname)) {
|
||||
/* found at least one section param */
|
||||
pos2 = pos1 + 1 + strlen(secname) + 1; // Remove the white space after the secname
|
||||
pos1 = strchr(pos2, '=');
|
||||
while (pos1 != NULL) {
|
||||
/* for each section param */
|
||||
key[0] = '\0';
|
||||
value[0] = '\0';
|
||||
*pos1 = ' ';
|
||||
if (sscanf(pos2, "%s %s", key, value) == 2) {
|
||||
params = lp_section_param_new(key, value);
|
||||
lp_config_add_section_param(cur, params);
|
||||
|
||||
pos2 += strlen(key) + strlen(value) + 2; // Remove the = sign + the white space after each param
|
||||
pos1 = strchr(pos2, '=');
|
||||
} else {
|
||||
ms_warning("parse section params error !");
|
||||
pos1 = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ms_warning("parse error!");
|
||||
}
|
||||
}
|
||||
}else {
|
||||
pos1=strchr(line,'=');
|
||||
if (pos1!=NULL){
|
||||
key[0]='\0';
|
||||
|
||||
*pos1='\0';
|
||||
if (sscanf(line,"%s",key)>0){
|
||||
|
||||
pos1++;
|
||||
pos2=strchr(pos1,'\r');
|
||||
if (pos2==NULL)
|
||||
pos2=strchr(pos1,'\n');
|
||||
if (pos2==NULL) pos2=pos1+strlen(pos1);
|
||||
else {
|
||||
*pos2='\0'; /*replace the '\n' */
|
||||
}
|
||||
/* remove ending white spaces */
|
||||
for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0';
|
||||
|
||||
if (pos2-pos1>=0){
|
||||
/* found a pair key,value */
|
||||
|
||||
if (cur!=NULL){
|
||||
item=lp_section_find_item(cur,key);
|
||||
if (item==NULL){
|
||||
lp_section_add_item(cur,lp_item_new(key,pos1));
|
||||
}else{
|
||||
ortp_free(item->value);
|
||||
item->value=ortp_strdup(pos1);
|
||||
}
|
||||
/*ms_message("Found %s=%s",key,pos1);*/
|
||||
}else{
|
||||
ms_warning("found key,item but no sections");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
void lp_config_parse(LpConfig *lpconfig, FILE *file){
|
||||
char tmp[MAX_LEN]= {'\0'};
|
||||
LpSection* current_section = NULL;
|
||||
|
||||
if (file==NULL) return;
|
||||
|
||||
while(fgets(tmp,MAX_LEN,file)!=NULL){
|
||||
tmp[sizeof(tmp) -1] = '\0';
|
||||
pos1=strchr(tmp,'[');
|
||||
if (pos1!=NULL && is_first_char(tmp,pos1) ){
|
||||
pos2=strchr(pos1,']');
|
||||
if (pos2!=NULL){
|
||||
secname[0]='\0';
|
||||
/* found section */
|
||||
*pos2='\0';
|
||||
nbs = sscanf(pos1+1,"%s",secname);
|
||||
if (nbs == 1 ){
|
||||
if (strlen(secname)>0){
|
||||
cur=lp_config_find_section (lpconfig,secname);
|
||||
if (cur==NULL){
|
||||
cur=lp_section_new(secname);
|
||||
lp_config_add_section(lpconfig,cur);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
ms_warning("parse error!");
|
||||
}
|
||||
}
|
||||
}else {
|
||||
pos1=strchr(tmp,'=');
|
||||
if (pos1!=NULL){
|
||||
key[0]='\0';
|
||||
|
||||
*pos1='\0';
|
||||
if (sscanf(tmp,"%s",key)>0){
|
||||
|
||||
pos1++;
|
||||
pos2=strchr(pos1,'\r');
|
||||
if (pos2==NULL)
|
||||
pos2=strchr(pos1,'\n');
|
||||
if (pos2==NULL) pos2=pos1+strlen(pos1);
|
||||
else {
|
||||
*pos2='\0'; /*replace the '\n' */
|
||||
}
|
||||
/* remove ending white spaces */
|
||||
for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0';
|
||||
|
||||
if (pos2-pos1>=0){
|
||||
/* found a pair key,value */
|
||||
|
||||
if (cur!=NULL){
|
||||
item=lp_section_find_item(cur,key);
|
||||
if (item==NULL){
|
||||
lp_section_add_item(cur,lp_item_new(key,pos1));
|
||||
}else{
|
||||
ms_free(item->value);
|
||||
item->value=strdup(pos1);
|
||||
}
|
||||
/*ms_message("Found %s=%s",key,pos1);*/
|
||||
}else{
|
||||
ms_warning("found key,item but no sections");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
current_section = lp_config_parse_line(lpconfig, tmp, current_section);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,9 +286,28 @@ LpConfig * lp_config_new(const char *filename){
|
|||
return lp_config_new_with_factory(filename, NULL);
|
||||
}
|
||||
|
||||
LpConfig * lp_config_new_from_buffer(const char *buffer){
|
||||
LpConfig* conf = lp_new0(LpConfig,1);
|
||||
conf->refcnt=1;
|
||||
LpSection* current_section = NULL;
|
||||
|
||||
char* ptr = ms_strdup(buffer);
|
||||
char* strtok_storage = NULL;
|
||||
char* line = strtok_r(ptr, "\n", &strtok_storage);
|
||||
|
||||
while( line != NULL ){
|
||||
current_section = lp_config_parse_line(conf,line,current_section);
|
||||
line = strtok_r(NULL, "\n", &strtok_storage);
|
||||
}
|
||||
|
||||
ms_free(ptr);
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
LpConfig *lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename) {
|
||||
LpConfig *lpconfig=lp_new0(LpConfig,1);
|
||||
|
||||
lpconfig->refcnt=1;
|
||||
if (config_filename!=NULL){
|
||||
ms_message("Using (r/w) config information from %s", config_filename);
|
||||
lpconfig->filename=ortp_strdup(config_filename);
|
||||
|
|
@ -263,23 +350,50 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename){
|
|||
}
|
||||
|
||||
void lp_item_set_value(LpItem *item, const char *value){
|
||||
free(item->value);
|
||||
char *prev_value=item->value;
|
||||
item->value=ortp_strdup(value);
|
||||
ortp_free(prev_value);
|
||||
}
|
||||
|
||||
|
||||
void lp_config_destroy(LpConfig *lpconfig){
|
||||
if (lpconfig->filename!=NULL) free(lpconfig->filename);
|
||||
static void _lp_config_destroy(LpConfig *lpconfig){
|
||||
if (lpconfig->filename!=NULL) ortp_free(lpconfig->filename);
|
||||
ms_list_for_each(lpconfig->sections,(void (*)(void*))lp_section_destroy);
|
||||
ms_list_free(lpconfig->sections);
|
||||
free(lpconfig);
|
||||
}
|
||||
|
||||
LpConfig *lp_config_ref(LpConfig *lpconfig){
|
||||
lpconfig->refcnt++;
|
||||
return lpconfig;
|
||||
}
|
||||
|
||||
void lp_config_unref(LpConfig *lpconfig){
|
||||
lpconfig->refcnt--;
|
||||
if (lpconfig->refcnt==0)
|
||||
_lp_config_destroy(lpconfig);
|
||||
}
|
||||
|
||||
void lp_config_destroy(LpConfig *lpconfig){
|
||||
lp_config_unref(lpconfig);
|
||||
}
|
||||
|
||||
void lp_section_remove_item(LpSection *sec, LpItem *item){
|
||||
sec->items=ms_list_remove(sec->items,(void *)item);
|
||||
lp_item_destroy(item);
|
||||
}
|
||||
|
||||
const char *lp_config_get_section_param_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value){
|
||||
LpSection *sec;
|
||||
LpSectionParam *param;
|
||||
sec = lp_config_find_section(lpconfig, section);
|
||||
if (sec != NULL) {
|
||||
param = lp_section_find_param(sec, key);
|
||||
if (param != NULL) return param->value;
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
const char *lp_config_get_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_string){
|
||||
LpSection *sec;
|
||||
LpItem *item;
|
||||
|
|
@ -398,10 +512,16 @@ void lp_item_write(LpItem *item, FILE *file){
|
|||
fprintf(file,"%s=%s\n",item->key,item->value);
|
||||
}
|
||||
|
||||
void lp_section_param_write(LpSectionParam *param, FILE *file){
|
||||
fprintf(file, " %s=%s", param->key, param->value);
|
||||
}
|
||||
|
||||
void lp_section_write(LpSection *sec, FILE *file){
|
||||
fprintf(file,"[%s]\n",sec->name);
|
||||
ms_list_for_each2(sec->items,(void (*)(void*, void*))lp_item_write,(void *)file);
|
||||
fprintf(file,"\n");
|
||||
fprintf(file, "[%s",sec->name);
|
||||
ms_list_for_each2(sec->params, (void (*)(void*, void*))lp_section_param_write, (void *)file);
|
||||
fprintf(file, "]\n");
|
||||
ms_list_for_each2(sec->items, (void (*)(void*, void*))lp_item_write, (void *)file);
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
||||
int lp_config_sync(LpConfig *lpconfig){
|
||||
|
|
@ -461,3 +581,37 @@ void lp_config_clean_section(LpConfig *lpconfig, const char *section){
|
|||
int lp_config_needs_commit(const LpConfig *lpconfig){
|
||||
return lpconfig->modified>0;
|
||||
}
|
||||
|
||||
static const char *DEFAULT_VALUES_SUFFIX = "_default_values";
|
||||
|
||||
int lp_config_get_default_int(const LpConfig *lpconfig, const char *section, const char *key, int default_value) {
|
||||
char default_section[MAX_LEN];
|
||||
strcpy(default_section, section);
|
||||
strcat(default_section, DEFAULT_VALUES_SUFFIX);
|
||||
|
||||
return lp_config_get_int(lpconfig, default_section, key, default_value);
|
||||
}
|
||||
|
||||
int64_t lp_config_get_default_int64(const LpConfig *lpconfig, const char *section, const char *key, int64_t default_value) {
|
||||
char default_section[MAX_LEN];
|
||||
strcpy(default_section, section);
|
||||
strcat(default_section, DEFAULT_VALUES_SUFFIX);
|
||||
|
||||
return lp_config_get_int64(lpconfig, default_section, key, default_value);
|
||||
}
|
||||
|
||||
float lp_config_get_default_float(const LpConfig *lpconfig, const char *section, const char *key, float default_value) {
|
||||
char default_section[MAX_LEN];
|
||||
strcpy(default_section, section);
|
||||
strcat(default_section, DEFAULT_VALUES_SUFFIX);
|
||||
|
||||
return lp_config_get_float(lpconfig, default_section, key, default_value);
|
||||
}
|
||||
|
||||
const char* lp_config_get_default_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value) {
|
||||
char default_section[MAX_LEN];
|
||||
strcpy(default_section, section);
|
||||
strcat(default_section, DEFAULT_VALUES_SUFFIX);
|
||||
|
||||
return lp_config_get_string(lpconfig, default_section, key, default_value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LPCONFIG_H
|
||||
#define LPCONFIG_H
|
||||
#include <mediastreamer2/mscommon.h>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
/**
|
||||
* The LpConfig object is used to manipulate a configuration file.
|
||||
*
|
||||
*
|
||||
* @ingroup misc
|
||||
* The format of the configuration file is a .ini like format:
|
||||
* - sections are defined in []
|
||||
|
|
@ -55,32 +55,28 @@ typedef struct _LpConfig LpConfig;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define LP_CONFIG_DEFAULT_STRING(config, name, default) \
|
||||
(config) ? (lp_config_get_string(config, "default_values", name, default)) : (default)
|
||||
|
||||
#define LP_CONFIG_DEFAULT_INT(config, name, default) \
|
||||
(config) ? (lp_config_get_int(config, "default_values", name, default)) : (default)
|
||||
|
||||
#define LP_CONFIG_DEFAULT_INT64(config, name, default) \
|
||||
(config) ? (lp_config_get_int64(config, "default_values", name, default)) : (default)
|
||||
|
||||
#define LP_CONFIG_DEFAULT_FLOAT(config, name, default) \
|
||||
(config) ? (lp_config_get_float(config, "default_values", name, default)) : (default)
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a LpConfig object from a user config file.
|
||||
*
|
||||
* The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed.
|
||||
* @ingroup misc
|
||||
* @param filename the filename of the config file to read to fill the instantiated LpConfig
|
||||
* @see lp_config_new_with_factory
|
||||
*/
|
||||
LINPHONE_PUBLIC LpConfig * lp_config_new(const char *filename);
|
||||
|
||||
/**
|
||||
* Instantiates a LpConfig object from a user provided buffer.
|
||||
* The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed.
|
||||
* @ingroup misc
|
||||
* @param buffer the buffer from which the lpconfig will be retrieved. We expect the buffer to be null-terminated.
|
||||
* @see lp_config_new_with_factory
|
||||
* @see lp_config_new
|
||||
*/
|
||||
LINPHONE_PUBLIC LpConfig * lp_config_new_from_buffer(const char *buffer);
|
||||
|
||||
/**
|
||||
* Instantiates a LpConfig object from a user config file and a factory config file.
|
||||
*
|
||||
* The caller of this constructor owns a reference. lp_config_unref() must be called when this object is no longer needed.
|
||||
* @ingroup misc
|
||||
* @param config_filename the filename of the user config file to read to fill the instantiated LpConfig
|
||||
* @param factory_config_filename the filename of the factory config file to read to fill the instantiated LpConfig
|
||||
|
|
@ -102,7 +98,7 @@ LINPHONE_PUBLIC int lp_config_read_file(LpConfig *lpconfig, const char *filename
|
|||
|
||||
/**
|
||||
* Retrieves a configuration item as a string, given its section, key, and default value.
|
||||
*
|
||||
*
|
||||
* @ingroup misc
|
||||
* The default value string is returned if the config item isn't found.
|
||||
**/
|
||||
|
|
@ -119,7 +115,7 @@ LINPHONE_PUBLIC bool_t lp_config_get_range(const LpConfig *lpconfig, const char
|
|||
|
||||
/**
|
||||
* Retrieves a configuration item as an integer, given its section, key, and default value.
|
||||
*
|
||||
*
|
||||
* @ingroup misc
|
||||
* The default integer value is returned if the config item isn't found.
|
||||
**/
|
||||
|
|
@ -127,7 +123,7 @@ LINPHONE_PUBLIC int lp_config_get_int(const LpConfig *lpconfig,const char *secti
|
|||
|
||||
/**
|
||||
* Retrieves a configuration item as a 64 bit integer, given its section, key, and default value.
|
||||
*
|
||||
*
|
||||
* @ingroup misc
|
||||
* The default integer value is returned if the config item isn't found.
|
||||
**/
|
||||
|
|
@ -135,14 +131,14 @@ LINPHONE_PUBLIC int64_t lp_config_get_int64(const LpConfig *lpconfig,const char
|
|||
|
||||
/**
|
||||
* Retrieves a configuration item as a float, given its section, key, and default value.
|
||||
*
|
||||
*
|
||||
* @ingroup misc
|
||||
* The default float value is returned if the config item isn't found.
|
||||
**/
|
||||
LINPHONE_PUBLIC float lp_config_get_float(const LpConfig *lpconfig,const char *section, const char *key, float default_value);
|
||||
|
||||
/**
|
||||
* Sets a string config item
|
||||
* Sets a string config item
|
||||
*
|
||||
* @ingroup misc
|
||||
**/
|
||||
|
|
@ -167,7 +163,7 @@ LINPHONE_PUBLIC void lp_config_set_int(LpConfig *lpconfig,const char *section, c
|
|||
*
|
||||
* @ingroup misc
|
||||
**/
|
||||
void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value);
|
||||
LINPHONE_PUBLIC void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *key, int value);
|
||||
|
||||
/**
|
||||
* Sets a 64 bits integer config item
|
||||
|
|
@ -181,11 +177,11 @@ LINPHONE_PUBLIC void lp_config_set_int64(LpConfig *lpconfig,const char *section,
|
|||
*
|
||||
* @ingroup misc
|
||||
**/
|
||||
LINPHONE_PUBLIC void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value);
|
||||
LINPHONE_PUBLIC void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value);
|
||||
|
||||
/**
|
||||
* Writes the config file to disk.
|
||||
*
|
||||
*
|
||||
* @ingroup misc
|
||||
**/
|
||||
LINPHONE_PUBLIC int lp_config_sync(LpConfig *lpconfig);
|
||||
|
|
@ -220,8 +216,62 @@ void lp_config_for_each_entry(const LpConfig *lpconfig, const char *section, voi
|
|||
|
||||
/*tells whether uncommited (with lp_config_sync()) modifications exist*/
|
||||
int lp_config_needs_commit(const LpConfig *lpconfig);
|
||||
void lp_config_destroy(LpConfig *cfg);
|
||||
|
||||
|
||||
LINPHONE_PUBLIC void lp_config_destroy(LpConfig *cfg);
|
||||
|
||||
/**
|
||||
* Retrieves a default configuration item as an integer, given its section, key, and default value.
|
||||
*
|
||||
* @ingroup misc
|
||||
* The default integer value is returned if the config item isn't found.
|
||||
**/
|
||||
LINPHONE_PUBLIC int lp_config_get_default_int(const LpConfig *lpconfig, const char *section, const char *key, int default_value);
|
||||
|
||||
/**
|
||||
* Retrieves a default configuration item as a 64 bit integer, given its section, key, and default value.
|
||||
*
|
||||
* @ingroup misc
|
||||
* The default integer value is returned if the config item isn't found.
|
||||
**/
|
||||
LINPHONE_PUBLIC int64_t lp_config_get_default_int64(const LpConfig *lpconfig, const char *section, const char *key, int64_t default_value);
|
||||
|
||||
/**
|
||||
* Retrieves a default configuration item as a float, given its section, key, and default value.
|
||||
*
|
||||
* @ingroup misc
|
||||
* The default float value is returned if the config item isn't found.
|
||||
**/
|
||||
LINPHONE_PUBLIC float lp_config_get_default_float(const LpConfig *lpconfig, const char *section, const char *key, float default_value);
|
||||
|
||||
/**
|
||||
* Retrieves a default configuration item as a string, given its section, key, and default value.
|
||||
*
|
||||
* @ingroup misc
|
||||
* The default value string is returned if the config item isn't found.
|
||||
**/
|
||||
LINPHONE_PUBLIC const char* lp_config_get_default_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value);
|
||||
|
||||
/**
|
||||
* Retrieves a section parameter item as a string, given its section and key.
|
||||
*
|
||||
* @ingroup misc
|
||||
* The default value string is returned if the config item isn't found.
|
||||
**/
|
||||
LINPHONE_PUBLIC const char* lp_config_get_section_param_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_value);
|
||||
|
||||
|
||||
/**
|
||||
* increment reference count
|
||||
* @ingroup misc
|
||||
**/
|
||||
LINPHONE_PUBLIC LpConfig *lp_config_ref(LpConfig *lpconfig);
|
||||
|
||||
/**
|
||||
* Decrement reference count, which will eventually free the object.
|
||||
* @ingroup misc
|
||||
**/
|
||||
LINPHONE_PUBLIC void lp_config_unref(LpConfig *lpconfig);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){
|
|||
ms_warning("Could not play %s",filename);
|
||||
return -1;
|
||||
}
|
||||
ms_filter_set_notify_callback (b->player,lsd_player_on_eop,b);
|
||||
ms_filter_add_notify_callback (b->player,lsd_player_on_eop,b,FALSE);
|
||||
lsd_player_configure(b);
|
||||
ms_filter_call_method_noarg (b->player,MS_PLAYER_START);
|
||||
return 0;
|
||||
|
|
@ -249,7 +249,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate,
|
|||
mp.pin=0;
|
||||
|
||||
lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd);
|
||||
ms_filter_set_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0]);
|
||||
ms_filter_add_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0],FALSE);
|
||||
for(i=1;i<MAX_BRANCHES;++i){
|
||||
mp.pin=i;
|
||||
lsd_player_init(&lsd->branches[i],mp,MS_FILE_PLAYER_ID,lsd);
|
||||
|
|
|
|||
452
coreapi/misc.c
452
coreapi/misc.c
|
|
@ -54,132 +54,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define pclose _pclose
|
||||
#endif
|
||||
|
||||
#if !defined(WIN32)
|
||||
|
||||
static char lock_name[80];
|
||||
static char lock_set=0;
|
||||
/* put a lock file in /tmp. this is called when linphone runs as a daemon*/
|
||||
int set_lock_file()
|
||||
{
|
||||
FILE *lockfile;
|
||||
|
||||
snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
|
||||
lockfile=fopen(lock_name,"w");
|
||||
if (lockfile==NULL)
|
||||
{
|
||||
printf("Failed to create lock file.\n");
|
||||
return(-1);
|
||||
}
|
||||
fprintf(lockfile,"%i",getpid());
|
||||
fclose(lockfile);
|
||||
lock_set=1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* looks if there is a lock file. If presents return its content (the pid of the already running linphone), if not found, returns -1*/
|
||||
int get_lock_file()
|
||||
{
|
||||
int pid;
|
||||
FILE *lockfile;
|
||||
|
||||
snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
|
||||
lockfile=fopen(lock_name,"r");
|
||||
if (lockfile==NULL)
|
||||
return(-1);
|
||||
if (fscanf(lockfile,"%i",&pid)!=1){
|
||||
ms_warning("Could not read pid in lock file.");
|
||||
fclose(lockfile);
|
||||
return -1;
|
||||
}
|
||||
fclose(lockfile);
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* remove the lock file if it was set*/
|
||||
int remove_lock_file()
|
||||
{
|
||||
int err=0;
|
||||
if (lock_set)
|
||||
{
|
||||
err=unlink(lock_name);
|
||||
lock_set=0;
|
||||
}
|
||||
return(err);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
char *int2str(int number)
|
||||
{
|
||||
char *numstr=ms_malloc(10);
|
||||
snprintf(numstr,10,"%i",number);
|
||||
return numstr;
|
||||
}
|
||||
|
||||
void check_sound_device(LinphoneCore *lc)
|
||||
{
|
||||
#ifdef _linux
|
||||
int fd=0;
|
||||
int len;
|
||||
int a;
|
||||
char *file=NULL;
|
||||
char *i810_audio=NULL;
|
||||
char *snd_pcm_oss=NULL;
|
||||
char *snd_mixer_oss=NULL;
|
||||
char *snd_pcm=NULL;
|
||||
fd=open("/proc/modules",O_RDONLY);
|
||||
|
||||
if (fd>0){
|
||||
/* read the entire /proc/modules file and check if sound conf seems correct */
|
||||
/*a=fstat(fd,&statbuf);
|
||||
if (a<0) ms_warning("Can't stat /proc/modules:%s.",strerror(errno));
|
||||
len=statbuf.st_size;
|
||||
if (len==0) ms_warning("/proc/modules has zero size!");
|
||||
*/
|
||||
/***** fstat does not work on /proc/modules for unknown reason *****/
|
||||
len=6000;
|
||||
file=ms_malloc(len+1);
|
||||
a=read(fd,file,len);
|
||||
if (a<len) file=ms_realloc(file,a+1);
|
||||
file[a]='\0';
|
||||
i810_audio=strstr(file,"i810_audio");
|
||||
if (i810_audio!=NULL){
|
||||
/* I'm sorry i put this warning in comments because
|
||||
* i don't use yet the right driver !! */
|
||||
/* lc->vtable.display_warning(lc,_("You are currently using the i810_audio driver.\nThis driver is buggy and so does not work with Linphone.\nWe suggest that you replace it by its equivalent ALSA driver,\neither with packages from your distribution, or by downloading\nALSA drivers at http://www.alsa-project.org."));*/
|
||||
goto end;
|
||||
}
|
||||
snd_pcm=strstr(file,"snd-pcm");
|
||||
if (snd_pcm!=NULL){
|
||||
snd_pcm_oss=strstr(file,"snd-pcm-oss");
|
||||
snd_mixer_oss=strstr(file,"snd-mixer-oss");
|
||||
if (snd_pcm_oss==NULL){
|
||||
lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the pcm oss emulation module\nis missing and linphone needs it. Please execute\n'modprobe snd-pcm-oss' as root to load it."));
|
||||
}
|
||||
if (snd_mixer_oss==NULL){
|
||||
lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the mixer oss emulation module\nis missing and linphone needs it. Please execute\n 'modprobe snd-mixer-oss' as root to load it."));
|
||||
}
|
||||
}
|
||||
}else {
|
||||
|
||||
ms_warning("Could not open /proc/modules.");
|
||||
}
|
||||
/* now check general volume. Some user forget to rise it and then complain that linphone is
|
||||
not working */
|
||||
/* but some other users complain that linphone should not change levels...
|
||||
if (lc->sound_conf.sndcard!=NULL){
|
||||
a=snd_card_get_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL);
|
||||
if (a<50){
|
||||
ms_warning("General level is quite low (%i). Linphone rises it up for you.",a);
|
||||
snd_card_set_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL,80);
|
||||
}
|
||||
}
|
||||
*/
|
||||
end:
|
||||
if (file!=NULL) ms_free(file);
|
||||
if (fd>0) close(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define UDP_HDR_SZ 8
|
||||
#define RTP_HDR_SZ 12
|
||||
|
|
@ -501,6 +375,10 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
|
|||
ms_warning("stun support is not implemented for ipv6");
|
||||
return -1;
|
||||
}
|
||||
if (call->media_ports[0].rtp_port==-1){
|
||||
ms_warning("Stun-only support not available for system random port");
|
||||
return -1;
|
||||
}
|
||||
if (server!=NULL){
|
||||
const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc);
|
||||
ortp_socket_t sock1=-1, sock2=-1;
|
||||
|
|
@ -520,10 +398,10 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
|
|||
lc->vtable.display_status(lc,_("Stun lookup in progress..."));
|
||||
|
||||
/*create the two audio and video RTP sockets, and send STUN message to our stun server */
|
||||
sock1=create_socket(call->audio_port);
|
||||
sock1=create_socket(call->media_ports[0].rtp_port);
|
||||
if (sock1==-1) return -1;
|
||||
if (video_enabled){
|
||||
sock2=create_socket(call->video_port);
|
||||
sock2=create_socket(call->media_ports[1].rtp_port);
|
||||
if (sock2==-1) return -1;
|
||||
}
|
||||
got_audio=FALSE;
|
||||
|
|
@ -637,12 +515,16 @@ static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addr
|
|||
}
|
||||
|
||||
void linphone_core_resolve_stun_server(LinphoneCore *lc){
|
||||
/*
|
||||
* WARNING: stun server resolution only done in IPv4.
|
||||
* TODO: use IPv6 resolution if linphone_core_ipv6_enabled()==TRUE and use V4Mapped addresses for ICE gathering.
|
||||
*/
|
||||
const char *server=lc->net_conf.stun_server;
|
||||
if (lc->sal && server){
|
||||
char host[NI_MAXHOST];
|
||||
int port=3478;
|
||||
linphone_parse_host_port(server,host,sizeof(host),&port);
|
||||
lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_UNSPEC,(SalResolverCallback)stun_server_resolved,lc);
|
||||
lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_INET,(SalResolverCallback)stun_server_resolved,lc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -685,8 +567,8 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
|
|||
video_check_list = ice_session_check_list(call->ice_session, 1);
|
||||
if (audio_check_list == NULL) return -1;
|
||||
|
||||
if (lc->sip_conf.ipv6_enabled){
|
||||
ms_warning("stun support is not implemented for ipv6");
|
||||
if (call->af==AF_INET6){
|
||||
ms_warning("Ice gathering is not implemented for ipv6");
|
||||
return -1;
|
||||
}
|
||||
ai=linphone_core_get_stun_server_addrinfo(lc);
|
||||
|
|
@ -703,14 +585,14 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
|
|||
return -1;
|
||||
}
|
||||
if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) {
|
||||
ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
|
||||
ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
|
||||
ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtp_port, 1, NULL);
|
||||
ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtcp_port, 2, NULL);
|
||||
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
|
||||
}
|
||||
if (call->params.has_video && (video_check_list != NULL)
|
||||
if (linphone_core_video_enabled(lc) && (video_check_list != NULL)
|
||||
&& (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) {
|
||||
ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
|
||||
ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
|
||||
ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtp_port, 1, NULL);
|
||||
ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtcp_port, 2, NULL);
|
||||
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
|
||||
}
|
||||
|
||||
|
|
@ -1005,7 +887,12 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
|
|||
}
|
||||
}
|
||||
for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) {
|
||||
ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
|
||||
IceCheckList *removed=ice_session_check_list(call->ice_session, i - 1);
|
||||
ice_session_remove_check_list(call->ice_session, removed);
|
||||
if (call->audiostream && call->audiostream->ms.ice_check_list==removed)
|
||||
call->audiostream->ms.ice_check_list=NULL;
|
||||
if (call->videostream && call->videostream->ms.ice_check_list==removed)
|
||||
call->videostream->ms.ice_check_list=NULL;
|
||||
}
|
||||
ice_session_check_mismatch(call->ice_session);
|
||||
} else {
|
||||
|
|
@ -1133,12 +1020,12 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
|
|||
socklen_t s;
|
||||
|
||||
memset(&hints,0,sizeof(hints));
|
||||
hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
|
||||
hints.ai_family=type;
|
||||
hints.ai_socktype=SOCK_DGRAM;
|
||||
/*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
|
||||
err=getaddrinfo(dest,"5060",&hints,&res);
|
||||
if (err!=0){
|
||||
ms_error("getaddrinfo() error: %s",gai_strerror(err));
|
||||
ms_error("getaddrinfo() error for %s : %s",dest, gai_strerror(err));
|
||||
return -1;
|
||||
}
|
||||
if (res==NULL){
|
||||
|
|
@ -1153,7 +1040,8 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
|
|||
}
|
||||
err=connect(sock,res->ai_addr,res->ai_addrlen);
|
||||
if (err<0) {
|
||||
ms_error("Error in connect: %s",strerror(errno));
|
||||
/*the network isn't reachable*/
|
||||
if (getSocketErrorCode()!=ENETUNREACH) ms_error("Error in connect: %s",strerror(errno));
|
||||
freeaddrinfo(res);
|
||||
close_socket(sock);
|
||||
return -1;
|
||||
|
|
@ -1178,9 +1066,13 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
|
|||
if (err!=0){
|
||||
ms_error("getnameinfo error: %s",strerror(errno));
|
||||
}
|
||||
/*avoid ipv6 link-local addresses*/
|
||||
if (type==AF_INET6 && strchr(result,'%')!=NULL){
|
||||
strcpy(result,"::1");
|
||||
close_socket(sock);
|
||||
return -1;
|
||||
}
|
||||
close_socket(sock);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1211,39 +1103,53 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
|
|||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void _linphone_core_configure_resolver(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
SalReason linphone_reason_to_sal(LinphoneReason reason){
|
||||
switch(reason){
|
||||
case LinphoneReasonNone:
|
||||
return SalReasonUnknown;
|
||||
return SalReasonNone;
|
||||
case LinphoneReasonNoResponse:
|
||||
return SalReasonUnknown;
|
||||
case LinphoneReasonBadCredentials:
|
||||
return SalReasonRequestTimeout;
|
||||
case LinphoneReasonForbidden:
|
||||
return SalReasonForbidden;
|
||||
case LinphoneReasonDeclined:
|
||||
return SalReasonDeclined;
|
||||
case LinphoneReasonNotFound:
|
||||
return SalReasonNotFound;
|
||||
case LinphoneReasonNotAnswered:
|
||||
case LinphoneReasonTemporarilyUnavailable:
|
||||
return SalReasonTemporarilyUnavailable;
|
||||
case LinphoneReasonBusy:
|
||||
return SalReasonBusy;
|
||||
case LinphoneReasonMedia:
|
||||
return SalReasonMedia;
|
||||
case LinphoneReasonNotAcceptable:
|
||||
return SalReasonNotAcceptable;
|
||||
case LinphoneReasonIOError:
|
||||
return SalReasonServiceUnavailable;
|
||||
case LinphoneReasonDoNotDisturb:
|
||||
return SalReasonDoNotDisturb;
|
||||
case LinphoneReasonUnauthorized:
|
||||
return SalReasonUnauthorized;
|
||||
case LinphoneReasonNotAcceptable:
|
||||
return SalReasonNotAcceptable;
|
||||
case LinphoneReasonUnsupportedContent:
|
||||
return SalReasonUnsupportedContent;
|
||||
case LinphoneReasonNoMatch:
|
||||
return SalReasonNoMatch;
|
||||
case LinphoneReasonMovedPermanently:
|
||||
return SalReasonMovedPermanently;
|
||||
case LinphoneReasonGone:
|
||||
return SalReasonGone;
|
||||
case LinphoneReasonAddressIncomplete:
|
||||
return SalReasonAddressIncomplete;
|
||||
case LinphoneReasonNotImplemented:
|
||||
return SalReasonNotImplemented;
|
||||
case LinphoneReasonBadGateway:
|
||||
return SalReasonBadGateway;
|
||||
case LinphoneReasonServerTimeout:
|
||||
return SalReasonServerTimeout;
|
||||
case LinphoneReasonNotAnswered:
|
||||
return SalReasonRequestTimeout;
|
||||
case LinphoneReasonUnknown:
|
||||
return SalReasonUnknown;
|
||||
}
|
||||
return SalReasonUnknown;
|
||||
}
|
||||
|
|
@ -1251,9 +1157,15 @@ SalReason linphone_reason_to_sal(LinphoneReason reason){
|
|||
LinphoneReason linphone_reason_from_sal(SalReason r){
|
||||
LinphoneReason ret=LinphoneReasonNone;
|
||||
switch(r){
|
||||
case SalReasonUnknown:
|
||||
case SalReasonNone:
|
||||
ret=LinphoneReasonNone;
|
||||
break;
|
||||
case SalReasonIOError:
|
||||
ret=LinphoneReasonIOError;
|
||||
break;
|
||||
case SalReasonUnknown:
|
||||
ret=LinphoneReasonUnknown;
|
||||
break;
|
||||
case SalReasonBusy:
|
||||
ret=LinphoneReasonBusy;
|
||||
break;
|
||||
|
|
@ -1266,8 +1178,8 @@ LinphoneReason linphone_reason_from_sal(SalReason r){
|
|||
case SalReasonForbidden:
|
||||
ret=LinphoneReasonBadCredentials;
|
||||
break;
|
||||
case SalReasonMedia:
|
||||
ret=LinphoneReasonMedia;
|
||||
case SalReasonNotAcceptable:
|
||||
ret=LinphoneReasonNotAcceptable;
|
||||
break;
|
||||
case SalReasonNotFound:
|
||||
ret=LinphoneReasonNotFound;
|
||||
|
|
@ -1276,7 +1188,7 @@ LinphoneReason linphone_reason_from_sal(SalReason r){
|
|||
ret=LinphoneReasonNone;
|
||||
break;
|
||||
case SalReasonTemporarilyUnavailable:
|
||||
ret=LinphoneReasonNone;
|
||||
ret=LinphoneReasonTemporarilyUnavailable;
|
||||
break;
|
||||
case SalReasonServiceUnavailable:
|
||||
ret=LinphoneReasonIOError;
|
||||
|
|
@ -1287,13 +1199,83 @@ LinphoneReason linphone_reason_from_sal(SalReason r){
|
|||
case SalReasonUnauthorized:
|
||||
ret=LinphoneReasonUnauthorized;
|
||||
break;
|
||||
case SalReasonNotAcceptable:
|
||||
ret=LinphoneReasonNotAcceptable;
|
||||
case SalReasonUnsupportedContent:
|
||||
ret=LinphoneReasonUnsupportedContent;
|
||||
break;
|
||||
case SalReasonNoMatch:
|
||||
ret=LinphoneReasonNoMatch;
|
||||
break;
|
||||
case SalReasonRequestTimeout:
|
||||
ret=LinphoneReasonNotAnswered;
|
||||
break;
|
||||
case SalReasonMovedPermanently:
|
||||
ret=LinphoneReasonMovedPermanently;
|
||||
break;
|
||||
case SalReasonGone:
|
||||
ret=LinphoneReasonGone;
|
||||
break;
|
||||
case SalReasonAddressIncomplete:
|
||||
ret=LinphoneReasonAddressIncomplete;
|
||||
break;
|
||||
case SalReasonNotImplemented:
|
||||
ret=LinphoneReasonNotImplemented;
|
||||
break;
|
||||
case SalReasonBadGateway:
|
||||
ret=LinphoneReasonBadGateway;
|
||||
break;
|
||||
case SalReasonServerTimeout:
|
||||
ret=LinphoneReasonServerTimeout;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reason code from the error info.
|
||||
* @param ei the error info.
|
||||
* @return a #LinphoneReason
|
||||
* @ingroup misc
|
||||
**/
|
||||
LinphoneReason linphone_error_info_get_reason(const LinphoneErrorInfo *ei){
|
||||
const SalErrorInfo *sei=(const SalErrorInfo*)ei;
|
||||
return linphone_reason_from_sal(sei->reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get textual phrase from the error info.
|
||||
* This is the text that is provided by the peer in the protocol (SIP).
|
||||
* @param ei the error info.
|
||||
* @return the error phrase
|
||||
* @ingroup misc
|
||||
**/
|
||||
const char *linphone_error_info_get_phrase(const LinphoneErrorInfo *ei){
|
||||
const SalErrorInfo *sei=(const SalErrorInfo*)ei;
|
||||
return sei->status_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides additional information regarding the failure.
|
||||
* With SIP protocol, the "Reason" and "Warning" headers are returned.
|
||||
* @param ei the error info.
|
||||
* @return more details about the failure.
|
||||
* @ingroup misc
|
||||
**/
|
||||
const char *linphone_error_info_get_details(const LinphoneErrorInfo *ei){
|
||||
const SalErrorInfo *sei=(const SalErrorInfo*)ei;
|
||||
return sei->warnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status code from the low level protocol (ex a SIP status code).
|
||||
* @param ei the error info.
|
||||
* @return the status code.
|
||||
* @ingroup misc
|
||||
**/
|
||||
int linphone_error_info_get_protocol_code(const LinphoneErrorInfo *ei){
|
||||
const SalErrorInfo *sei=(const SalErrorInfo*)ei;
|
||||
return sei->protocol_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the mediastreamer2 filter to be used for rendering video.
|
||||
* This is for advanced users of the library, mainly to workaround hardware/driver bugs.
|
||||
|
|
@ -1311,5 +1293,153 @@ const char *linphone_core_get_video_display_filter(LinphoneCore *lc){
|
|||
return lp_config_get_string(lc->config,"video","displaytype",NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a task into the main loop. The data pointer must remain valid until the task is completed.
|
||||
* task_fun must return BELLE_SIP_STOP when job is finished.
|
||||
**/
|
||||
void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description){
|
||||
belle_sip_source_t *s=sal_create_timer(lc->sal,task_fun,data, 20, task_description);
|
||||
belle_sip_object_unref(s);
|
||||
}
|
||||
|
||||
static int get_unique_transport(LinphoneCore *lc, LinphoneTransportType *type, int *port){
|
||||
LCSipTransports tp;
|
||||
linphone_core_get_sip_transports(lc,&tp);
|
||||
if (tp.tcp_port==0 && tp.tls_port==0 && tp.udp_port!=0){
|
||||
*type=LinphoneTransportUdp;
|
||||
*port=tp.udp_port;
|
||||
return 0;
|
||||
}else if (tp.tcp_port==0 && tp.udp_port==0 && tp.tls_port!=0){
|
||||
*type=LinphoneTransportTls;
|
||||
*port=tp.tls_port;
|
||||
return 0;
|
||||
}else if (tp.tcp_port!=0 && tp.udp_port==0 && tp.tls_port==0){
|
||||
*type=LinphoneTransportTcp;
|
||||
*port=tp.tcp_port;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void linphone_core_migrate_proxy_config(LinphoneCore *lc, LinphoneTransportType type){
|
||||
const MSList *elem;
|
||||
for(elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){
|
||||
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;
|
||||
const char *proxy=linphone_proxy_config_get_addr(cfg);
|
||||
const char *route=linphone_proxy_config_get_route(cfg);
|
||||
LinphoneAddress *proxy_addr=linphone_address_new(proxy);
|
||||
LinphoneAddress *route_addr=NULL;
|
||||
char *tmp;
|
||||
if (route) route_addr=linphone_address_new(route);
|
||||
if (proxy_addr){
|
||||
linphone_address_set_transport(proxy_addr,type);
|
||||
tmp=linphone_address_as_string(proxy_addr);
|
||||
linphone_proxy_config_set_server_addr(cfg,tmp);
|
||||
ms_free(tmp);
|
||||
linphone_address_destroy(proxy_addr);
|
||||
}
|
||||
if (route_addr){
|
||||
linphone_address_set_transport(route_addr,type);
|
||||
tmp=linphone_address_as_string(route_addr);
|
||||
linphone_proxy_config_set_route(cfg,tmp);
|
||||
ms_free(tmp);
|
||||
linphone_address_destroy(route_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate configuration so that all SIP transports are enabled.
|
||||
* Versions of linphone < 3.7 did not support using multiple SIP transport simultaneously.
|
||||
* This function helps application to migrate the configuration so that all transports are enabled.
|
||||
* Existing proxy configuration are added a transport parameter so that they continue using the unique transport that was set previously.
|
||||
* This function must be used just after creating the core, before any call to linphone_core_iterate()
|
||||
* @param lc the linphone core
|
||||
* @returns 1 if migration was done, 0 if not done because unnecessary or already done, -1 in case of error.
|
||||
* @ingroup initializing
|
||||
**/
|
||||
int linphone_core_migrate_to_multi_transport(LinphoneCore *lc){
|
||||
if (!lp_config_get_int(lc->config,"sip","multi_transport_migration_done",0)){
|
||||
LinphoneTransportType tpt;
|
||||
int port;
|
||||
if (get_unique_transport(lc,&tpt,&port)==0){
|
||||
LCSipTransports newtp={0};
|
||||
if (lp_config_get_int(lc->config,"sip","sip_random_port",0))
|
||||
port=-1;
|
||||
ms_message("Core is using a single SIP transport, migrating proxy config and enabling multi-transport.");
|
||||
linphone_core_migrate_proxy_config(lc,tpt);
|
||||
newtp.udp_port=port;
|
||||
newtp.tcp_port=port;
|
||||
newtp.tls_port=LC_SIP_TRANSPORT_RANDOM;
|
||||
lp_config_set_string(lc->config, "sip","sip_random_port",NULL); /*remove*/
|
||||
linphone_core_set_sip_transports(lc,&newtp);
|
||||
}
|
||||
lp_config_set_int(lc->config,"sip","multi_transport_migration_done",1);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile){
|
||||
LinphoneToneDescription *obj=ms_new0(LinphoneToneDescription,1);
|
||||
obj->reason=reason;
|
||||
obj->toneid=id;
|
||||
obj->audiofile=audiofile ? ms_strdup(audiofile) : NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
void linphone_tone_description_destroy(LinphoneToneDescription *obj){
|
||||
if (obj->audiofile) ms_free(obj->audiofile);
|
||||
ms_free(obj);
|
||||
}
|
||||
|
||||
LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason){
|
||||
const MSList *elem;
|
||||
for (elem=lc->tones;elem!=NULL;elem=elem->next){
|
||||
LinphoneToneDescription *tone=(LinphoneToneDescription*)elem->data;
|
||||
if (tone->reason==reason) return tone;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id){
|
||||
const MSList *elem;
|
||||
for (elem=lc->tones;elem!=NULL;elem=elem->next){
|
||||
LinphoneToneDescription *tone=(LinphoneToneDescription*)elem->data;
|
||||
if (tone->toneid==id && tone->reason==LinphoneReasonNone && tone->audiofile!=NULL) return tone->audiofile;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile){
|
||||
LinphoneToneDescription *tone=linphone_core_get_call_error_tone(lc,reason);
|
||||
if (tone){
|
||||
lc->tones=ms_list_remove(lc->tones,tone);
|
||||
linphone_tone_description_destroy(tone);
|
||||
}
|
||||
tone=linphone_tone_description_new(reason,id,audiofile);
|
||||
lc->tones=ms_list_append(lc->tones,tone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign an audio file to be played locally upon call failure, for a given reason.
|
||||
* @param lc the core
|
||||
* @param reason the #LinphoneReason representing the failure error code.
|
||||
* @param audiofile a wav file to be played when such call failure happens.
|
||||
* @ingroup misc
|
||||
**/
|
||||
void linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, const char *audiofile){
|
||||
_linphone_core_set_tone(lc,reason,LinphoneToneUndefined, audiofile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign an audio file to be played as a specific tone id.
|
||||
* This function typically allows to customize telephony tones per country.
|
||||
* @param lc the core
|
||||
* @param id the tone id
|
||||
* @param audiofile a wav file to be played.
|
||||
**/
|
||||
void linphone_core_set_tone(LinphoneCore *lc, LinphoneToneID id, const char *audiofile){
|
||||
_linphone_core_set_tone(lc, LinphoneReasonNone, id, audiofile);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
|
|||
result->ice_completed = local_cap->ice_completed;
|
||||
memcpy(result->ice_candidates, local_cap->ice_candidates, sizeof(result->ice_candidates));
|
||||
memcpy(result->ice_remote_candidates, local_cap->ice_remote_candidates, sizeof(result->ice_remote_candidates));
|
||||
strcpy(result->name,local_cap->name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -272,14 +273,18 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
|
|||
const SalMediaDescription *remote_answer,
|
||||
SalMediaDescription *result){
|
||||
int i,j;
|
||||
|
||||
const SalStreamDescription *ls,*rs;
|
||||
|
||||
for(i=0,j=0;i<local_offer->n_total_streams;++i){
|
||||
ms_message("Processing for stream %i",i);
|
||||
ls=&local_offer->streams[i];
|
||||
rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type);
|
||||
if (rs) {
|
||||
initiate_outgoing(ls,rs,&result->streams[j]);
|
||||
memcpy(&result->streams[i].rtcp_xr, &ls->rtcp_xr, sizeof(result->streams[i].rtcp_xr));
|
||||
if ((ls->rtcp_xr.enabled == TRUE) && (rs->rtcp_xr.enabled == FALSE)) {
|
||||
result->streams[i].rtcp_xr.enabled = FALSE;
|
||||
}
|
||||
++j;
|
||||
}
|
||||
else ms_warning("No matching stream for %i",i);
|
||||
|
|
@ -288,9 +293,43 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer,
|
|||
result->n_total_streams=local_offer->n_total_streams;
|
||||
result->bandwidth=remote_answer->bandwidth;
|
||||
strcpy(result->addr,remote_answer->addr);
|
||||
memcpy(&result->rtcp_xr, &local_offer->rtcp_xr, sizeof(result->rtcp_xr));
|
||||
if ((local_offer->rtcp_xr.enabled == TRUE) && (remote_answer->rtcp_xr.enabled == FALSE)) {
|
||||
result->rtcp_xr.enabled = FALSE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool_t local_stream_not_already_used(const SalMediaDescription *result, const SalStreamDescription *stream){
|
||||
int i;
|
||||
for(i=0;i<result->n_total_streams;++i){
|
||||
const SalStreamDescription *ss=&result->streams[i];
|
||||
if (strcmp(ss->name,stream->name)==0){
|
||||
ms_message("video stream already used in answer");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*in answering mode, we consider that if we are able to make SAVP, then we can do AVP as well*/
|
||||
static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote){
|
||||
if (local==remote) return TRUE;
|
||||
if (remote==SalProtoRtpAvp && local==SalProtoRtpSavp) return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static const SalStreamDescription *find_local_matching_stream(const SalMediaDescription *result, const SalMediaDescription *local_capabilities, const SalStreamDescription *remote_stream){
|
||||
int i;
|
||||
for(i=0;i<local_capabilities->n_active_streams;++i){
|
||||
const SalStreamDescription *ss=&local_capabilities->streams[i];
|
||||
if (ss->type==remote_stream->type && proto_compatible(ss->proto,remote_stream->proto)
|
||||
&& local_stream_not_already_used(result,ss)) return ss;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a media description to run the streams with, based on the local capabilities and
|
||||
* and the received offer.
|
||||
|
|
@ -305,17 +344,27 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
|
|||
result->n_active_streams=0;
|
||||
for(i=0;i<remote_offer->n_total_streams;++i){
|
||||
rs=&remote_offer->streams[i];
|
||||
if (rs->proto!=SalProtoUnknown){
|
||||
ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type);
|
||||
/* if matching failed, and remote proposes Avp only, ask for local Savp streams */
|
||||
if (!ls && rs->proto == SalProtoRtpAvp) {
|
||||
ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,SalProtoRtpSavp,rs->type);
|
||||
}
|
||||
if (rs->proto!=SalProtoOther){
|
||||
ls=find_local_matching_stream(result,local_capabilities,rs);
|
||||
}else ms_warning("Unknown protocol for mline %i, declining",i);
|
||||
if (ls){
|
||||
initiate_incoming(ls,rs,&result->streams[i],one_matching_codec);
|
||||
if (result->streams[i].rtp_port!=0) result->n_active_streams++;
|
||||
|
||||
// Handle media RTCP XR attribute
|
||||
memset(&result->streams[i].rtcp_xr, 0, sizeof(result->streams[i].rtcp_xr));
|
||||
if (rs->rtcp_xr.enabled == TRUE) {
|
||||
const OrtpRtcpXrConfiguration *rtcp_xr_conf = NULL;
|
||||
if (ls->rtcp_xr.enabled == TRUE) rtcp_xr_conf = &ls->rtcp_xr;
|
||||
else if (local_capabilities->rtcp_xr.enabled == TRUE) rtcp_xr_conf = &local_capabilities->rtcp_xr;
|
||||
if ((rtcp_xr_conf != NULL) && (ls->dir == SalStreamSendRecv)) {
|
||||
memcpy(&result->streams[i].rtcp_xr, rtcp_xr_conf, sizeof(result->streams[i].rtcp_xr));
|
||||
} else {
|
||||
result->streams[i].rtcp_xr.enabled = TRUE;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
ms_message("Declining mline %i, no corresponding stream in local capabilities description.",i);
|
||||
/* create an inactive stream for the answer, as there where no matching stream in local capabilities */
|
||||
result->streams[i].dir=SalStreamInactive;
|
||||
result->streams[i].rtp_port=0;
|
||||
|
|
@ -324,6 +373,9 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
|
|||
if (rs->type==SalOther){
|
||||
strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1);
|
||||
}
|
||||
if (rs->proto==SalProtoOther){
|
||||
strncpy(result->streams[i].proto_other,rs->proto_other,sizeof(rs->proto_other)-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
result->n_total_streams=i;
|
||||
|
|
@ -336,5 +388,18 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities
|
|||
strcpy(result->ice_ufrag, local_capabilities->ice_ufrag);
|
||||
result->ice_lite = local_capabilities->ice_lite;
|
||||
result->ice_completed = local_capabilities->ice_completed;
|
||||
|
||||
strcpy(result->name,local_capabilities->name);
|
||||
|
||||
// Handle session RTCP XR attribute
|
||||
memset(&result->rtcp_xr, 0, sizeof(result->rtcp_xr));
|
||||
if (remote_offer->rtcp_xr.enabled == TRUE) {
|
||||
if ((local_capabilities->rtcp_xr.enabled == TRUE) && (local_capabilities->dir == SalStreamSendRecv)) {
|
||||
memcpy(&result->rtcp_xr, &local_capabilities->rtcp_xr, sizeof(result->rtcp_xr));
|
||||
} else {
|
||||
result->rtcp_xr.enabled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,15 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "lpconfig.h"
|
||||
#include "linphonepresence.h"
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/xmlwriter.h>
|
||||
#include <libxml/xpath.h>
|
||||
#include <libxml/xpathInternals.h>
|
||||
|
||||
|
||||
#define XMLPARSING_BUFFER_LEN 2048
|
||||
#define MAX_XPATH_LENGTH 256
|
||||
|
||||
|
||||
|
||||
extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol);
|
||||
|
|
@ -83,13 +74,6 @@ struct _LinphonePresenceModel {
|
|||
MSList *notes; /**< A list of _LinphonePresenceNote structures. */
|
||||
};
|
||||
|
||||
typedef struct _xmlparsing_context {
|
||||
xmlDoc *doc;
|
||||
xmlXPathContextPtr xpath_ctx;
|
||||
char errorBuffer[XMLPARSING_BUFFER_LEN];
|
||||
char warningBuffer[XMLPARSING_BUFFER_LEN];
|
||||
} xmlparsing_context_t;
|
||||
|
||||
|
||||
static const char *person_prefix = "/pidf:presence/dm:person";
|
||||
|
||||
|
|
@ -98,38 +82,6 @@ static const char *person_prefix = "/pidf:presence/dm:person";
|
|||
* PRIVATE FUNCTIONS *
|
||||
****************************************************************************/
|
||||
|
||||
static xmlparsing_context_t * xmlparsing_context_new() {
|
||||
xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t));
|
||||
if (xmlCtx != NULL) {
|
||||
xmlCtx->doc = NULL;
|
||||
xmlCtx->xpath_ctx = NULL;
|
||||
xmlCtx->errorBuffer[0] = '\0';
|
||||
xmlCtx->warningBuffer[0] = '\0';
|
||||
}
|
||||
return xmlCtx;
|
||||
}
|
||||
|
||||
static void xmlparsing_context_destroy(xmlparsing_context_t *ctx) {
|
||||
if (ctx->doc != NULL) {
|
||||
xmlFreeDoc(ctx->doc);
|
||||
ctx->doc = NULL;
|
||||
}
|
||||
if (ctx->xpath_ctx != NULL) {
|
||||
xmlXPathFreeContext(ctx->xpath_ctx);
|
||||
ctx->xpath_ctx = NULL;
|
||||
}
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static void xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) {
|
||||
xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx;
|
||||
int sl = strlen(xmlCtx->errorBuffer);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
static char * generate_presence_id(void) {
|
||||
|
|
@ -1183,45 +1135,6 @@ void * linphone_presence_note_get_user_data(LinphonePresenceNote *note) {
|
|||
* XML PRESENCE INTERNAL HANDLING *
|
||||
****************************************************************************/
|
||||
|
||||
static int create_xml_xpath_context(xmlparsing_context_t *xml_ctx) {
|
||||
if (xml_ctx->xpath_ctx != NULL) {
|
||||
xmlXPathFreeContext(xml_ctx->xpath_ctx);
|
||||
}
|
||||
xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc);
|
||||
if (xml_ctx->xpath_ctx == NULL) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char * get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) {
|
||||
xmlXPathObjectPtr xpath_obj;
|
||||
xmlChar *text = NULL;
|
||||
int i;
|
||||
|
||||
xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx);
|
||||
if (xpath_obj != NULL) {
|
||||
if (xpath_obj->nodesetval != NULL) {
|
||||
xmlNodeSetPtr nodes = xpath_obj->nodesetval;
|
||||
for (i = 0; i < nodes->nodeNr; i++) {
|
||||
xmlNodePtr node = nodes->nodeTab[i];
|
||||
if (node->children != NULL) {
|
||||
text = xmlNodeListGetString(xml_ctx->doc, node->children, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlXPathFreeObject(xpath_obj);
|
||||
}
|
||||
|
||||
return (char *)text;
|
||||
}
|
||||
|
||||
static void free_xml_text_content(const char *text) {
|
||||
xmlFree((xmlChar *)text);
|
||||
}
|
||||
|
||||
static xmlXPathObjectPtr get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) {
|
||||
return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx);
|
||||
}
|
||||
|
||||
static const char *service_prefix = "/pidf:presence/pidf:tuple";
|
||||
|
||||
static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx, LinphonePresenceService *service, unsigned int service_idx) {
|
||||
|
|
@ -1233,19 +1146,19 @@ static int process_pidf_xml_presence_service_notes(xmlparsing_context_t *xml_ctx
|
|||
int i;
|
||||
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note", service_prefix, service_idx);
|
||||
note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
if ((note_object != NULL) && (note_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= note_object->nodesetval->nodeNr; i++) {
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]", service_prefix, service_idx, i);
|
||||
note_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
note_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if (note_str == NULL) continue;
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:note[%i]/@xml:lang", service_prefix, service_idx, i);
|
||||
lang = get_xml_text_content(xml_ctx, xpath_str);
|
||||
lang = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
|
||||
note = linphone_presence_note_new(note_str, lang);
|
||||
presence_service_add_note(service, note);
|
||||
if (lang != NULL) free_xml_text_content(lang);
|
||||
free_xml_text_content(note_str);
|
||||
if (lang != NULL) linphone_free_xml_text_content(lang);
|
||||
linphone_free_xml_text_content(note_str);
|
||||
}
|
||||
}
|
||||
if (note_object != NULL) xmlXPathFreeObject(note_object);
|
||||
|
|
@ -1264,11 +1177,11 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin
|
|||
LinphonePresenceBasicStatus basic_status;
|
||||
int i;
|
||||
|
||||
service_object = get_xml_xpath_object_for_node_list(xml_ctx, service_prefix);
|
||||
service_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, service_prefix);
|
||||
if ((service_object != NULL) && (service_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= service_object->nodesetval->nodeNr; i++) {
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:status/pidf:basic", service_prefix, i);
|
||||
basic_status_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
basic_status_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if (basic_status_str == NULL)
|
||||
continue;
|
||||
|
||||
|
|
@ -1278,33 +1191,33 @@ static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, Lin
|
|||
basic_status = LinphonePresenceBasicStatusClosed;
|
||||
} else {
|
||||
/* Invalid value for basic status. */
|
||||
free_xml_text_content(basic_status_str);
|
||||
linphone_free_xml_text_content(basic_status_str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", service_prefix, i);
|
||||
timestamp_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
timestamp_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:contact", service_prefix, i);
|
||||
contact_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
contact_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", service_prefix, i);
|
||||
service_id_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
service_id_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
service = presence_service_new(service_id_str, basic_status);
|
||||
if (service != NULL) {
|
||||
if (timestamp_str != NULL) {
|
||||
presence_service_set_timestamp(service, parse_timestamp(timestamp_str));
|
||||
free_xml_text_content(timestamp_str);
|
||||
linphone_free_xml_text_content(timestamp_str);
|
||||
}
|
||||
if (contact_str != NULL) {
|
||||
linphone_presence_service_set_contact(service, contact_str);
|
||||
free_xml_text_content(contact_str);
|
||||
linphone_free_xml_text_content(contact_str);
|
||||
}
|
||||
process_pidf_xml_presence_service_notes(xml_ctx, service, i);
|
||||
linphone_presence_model_add_service(model, service);
|
||||
}
|
||||
free_xml_text_content(basic_status_str);
|
||||
if (service_id_str != NULL) free_xml_text_content(service_id_str);
|
||||
linphone_free_xml_text_content(basic_status_str);
|
||||
if (service_id_str != NULL) linphone_free_xml_text_content(service_id_str);
|
||||
}
|
||||
}
|
||||
if (service_object != NULL) xmlXPathFreeObject(service_object);
|
||||
|
|
@ -1333,11 +1246,11 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml
|
|||
int err = 0;
|
||||
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities", person_prefix, person_idx);
|
||||
activities_nodes_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
activities_nodes_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
if ((activities_nodes_object != NULL) && (activities_nodes_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= activities_nodes_object->nodesetval->nodeNr; i++) {
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities[%i]/rpid:*", person_prefix, person_idx, i);
|
||||
activities_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
activities_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
if ((activities_object != NULL) && (activities_object->nodesetval != NULL)) {
|
||||
for (j = 0; j < activities_object->nodesetval->nodeNr; j++) {
|
||||
activity_node = activities_object->nodesetval->nodeTab[j];
|
||||
|
|
@ -1345,14 +1258,14 @@ static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml
|
|||
LinphonePresenceActivityType acttype;
|
||||
description = (const char *)xmlNodeGetContent(activity_node);
|
||||
if ((description != NULL) && (description[0] == '\0')) {
|
||||
free_xml_text_content(description);
|
||||
linphone_free_xml_text_content(description);
|
||||
description = NULL;
|
||||
}
|
||||
err = activity_name_to_presence_activity_type((const char *)activity_node->name, &acttype);
|
||||
if (err < 0) break;
|
||||
activity = linphone_presence_activity_new(acttype, description);
|
||||
linphone_presence_person_add_activity(person, activity);
|
||||
if (description != NULL) free_xml_text_content(description);
|
||||
if (description != NULL) linphone_free_xml_text_content(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1374,37 +1287,37 @@ static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx,
|
|||
int i;
|
||||
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note", person_prefix, person_idx);
|
||||
note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
if ((note_object != NULL) && (note_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= note_object->nodesetval->nodeNr; i++) {
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]", person_prefix, person_idx, i);
|
||||
note_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
note_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if (note_str == NULL) continue;
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/rpid:activities/rpid:note[%i]/@xml:lang", person_prefix, person_idx, i);
|
||||
lang = get_xml_text_content(xml_ctx, xpath_str);
|
||||
lang = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
|
||||
note = linphone_presence_note_new(note_str, lang);
|
||||
presence_person_add_activities_note(person, note);
|
||||
if (lang != NULL) free_xml_text_content(lang);
|
||||
free_xml_text_content(note_str);
|
||||
if (lang != NULL) linphone_free_xml_text_content(lang);
|
||||
linphone_free_xml_text_content(note_str);
|
||||
}
|
||||
}
|
||||
if (note_object != NULL) xmlXPathFreeObject(note_object);
|
||||
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note", person_prefix, person_idx);
|
||||
note_object = get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, xpath_str);
|
||||
if ((note_object != NULL) && (note_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= note_object->nodesetval->nodeNr; i++) {
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]", person_prefix, person_idx, i);
|
||||
note_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
note_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if (note_str == NULL) continue;
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/dm:note[%i]/@xml:lang", person_prefix, person_idx, i);
|
||||
lang = get_xml_text_content(xml_ctx, xpath_str);
|
||||
lang = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
|
||||
note = linphone_presence_note_new(note_str, lang);
|
||||
presence_person_add_note(person, note);
|
||||
if (lang != NULL) free_xml_text_content(lang);
|
||||
free_xml_text_content(note_str);
|
||||
if (lang != NULL) linphone_free_xml_text_content(lang);
|
||||
linphone_free_xml_text_content(note_str);
|
||||
}
|
||||
}
|
||||
if (note_object != NULL) xmlXPathFreeObject(note_object);
|
||||
|
|
@ -1422,13 +1335,13 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp
|
|||
int i;
|
||||
int err = 0;
|
||||
|
||||
person_object = get_xml_xpath_object_for_node_list(xml_ctx, person_prefix);
|
||||
person_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, person_prefix);
|
||||
if ((person_object != NULL) && (person_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= person_object->nodesetval->nodeNr; i++) {
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/@id", person_prefix, i);
|
||||
person_id_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
person_id_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", person_prefix, i);
|
||||
person_timestamp_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
person_timestamp_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if (person_timestamp_str == NULL)
|
||||
timestamp = time(NULL);
|
||||
else
|
||||
|
|
@ -1446,8 +1359,8 @@ static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, Linp
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (person_id_str != NULL) free_xml_text_content(person_id_str);
|
||||
if (person_timestamp_str != NULL) free_xml_text_content(person_timestamp_str);
|
||||
if (person_id_str != NULL) linphone_free_xml_text_content(person_id_str);
|
||||
if (person_timestamp_str != NULL) linphone_free_xml_text_content(person_timestamp_str);
|
||||
}
|
||||
}
|
||||
if (person_object != NULL) xmlXPathFreeObject(person_object);
|
||||
|
|
@ -1467,19 +1380,19 @@ static int process_pidf_xml_presence_notes(xmlparsing_context_t *xml_ctx, Linpho
|
|||
const char *lang;
|
||||
int i;
|
||||
|
||||
note_object = get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/pidf:note");
|
||||
note_object = linphone_get_xml_xpath_object_for_node_list(xml_ctx, "/pidf:presence/pidf:note");
|
||||
if ((note_object != NULL) && (note_object->nodesetval != NULL)) {
|
||||
for (i = 1; i <= note_object->nodesetval->nodeNr; i++) {
|
||||
snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]", i);
|
||||
note_str = get_xml_text_content(xml_ctx, xpath_str);
|
||||
note_str = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
if (note_str == NULL) continue;
|
||||
snprintf(xpath_str, sizeof(xpath_str), "/pidf:presence/pidf:note[%i]/@xml:lang", i);
|
||||
lang = get_xml_text_content(xml_ctx, xpath_str);
|
||||
lang = linphone_get_xml_text_content(xml_ctx, xpath_str);
|
||||
|
||||
note = linphone_presence_note_new(note_str, lang);
|
||||
presence_model_add_note(model, note);
|
||||
if (lang != NULL) free_xml_text_content(lang);
|
||||
free_xml_text_content(note_str);
|
||||
if (lang != NULL) linphone_free_xml_text_content(lang);
|
||||
linphone_free_xml_text_content(note_str);
|
||||
}
|
||||
}
|
||||
if (note_object != NULL) xmlXPathFreeObject(note_object);
|
||||
|
|
@ -1491,7 +1404,7 @@ static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing
|
|||
LinphonePresenceModel *model = NULL;
|
||||
int err;
|
||||
|
||||
if (create_xml_xpath_context(xml_ctx) < 0)
|
||||
if (linphone_create_xml_xpath_context(xml_ctx) < 0)
|
||||
return NULL;
|
||||
|
||||
model = linphone_presence_model_new();
|
||||
|
|
@ -1563,8 +1476,8 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){
|
|||
cfg=linphone_core_lookup_known_proxy(lc,uri);
|
||||
if (cfg!=NULL){
|
||||
if (cfg->op){
|
||||
if (sal_op_get_contact(cfg->op)) {
|
||||
sal_op_set_contact (op,sal_op_get_contact(cfg->op));
|
||||
if (sal_op_get_contact_address(cfg->op)) {
|
||||
sal_op_set_contact_address (op,sal_op_get_contact_address(cfg->op));
|
||||
ms_message("Contact for next subscribe answer has been fixed using proxy "/*to %s",fixed_contact*/);
|
||||
}
|
||||
}
|
||||
|
|
@ -1606,15 +1519,15 @@ void linphone_notify_parse_presence(SalOp *op, const char *content_type, const c
|
|||
}
|
||||
|
||||
if (strcmp(content_subtype, "pidf+xml") == 0) {
|
||||
xml_ctx = xmlparsing_context_new();
|
||||
xmlSetGenericErrorFunc(xml_ctx, xmlparsing_genericxml_error);
|
||||
xml_ctx = linphone_xmlparsing_context_new();
|
||||
xmlSetGenericErrorFunc(xml_ctx, linphone_xmlparsing_genericxml_error);
|
||||
xml_ctx->doc = xmlReadDoc((const unsigned char*)body, 0, NULL, 0);
|
||||
if (xml_ctx->doc != NULL) {
|
||||
model = process_pidf_xml_presence_notification(xml_ctx);
|
||||
} else {
|
||||
ms_warning("Wrongly formatted presence XML: %s", xml_ctx->errorBuffer);
|
||||
}
|
||||
xmlparsing_context_destroy(xml_ctx);
|
||||
linphone_xmlparsing_context_destroy(xml_ctx);
|
||||
} else {
|
||||
ms_error("Unknown content type '%s/%s' for presence", content_type, content_subtype);
|
||||
}
|
||||
|
|
@ -1896,7 +1809,7 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen
|
|||
if ((model == NULL) || (model->services == NULL)) {
|
||||
err = write_xml_presence_service(writer, NULL, contact);
|
||||
} else {
|
||||
struct _presence_service_obj_st st;
|
||||
struct _presence_service_obj_st st={0};
|
||||
st.writer = writer;
|
||||
st.contact = contact;
|
||||
st.err = &err;
|
||||
|
|
@ -1904,13 +1817,13 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen
|
|||
}
|
||||
}
|
||||
if ((err >= 0) && (model != NULL)) {
|
||||
struct _presence_person_obj_st st;
|
||||
struct _presence_person_obj_st st={0};
|
||||
st.writer = writer;
|
||||
st.err = &err;
|
||||
ms_list_for_each2(model->persons, (MSIterate2Func)write_xml_presence_person_obj, &st);
|
||||
}
|
||||
if ((err >= 0) && (model != NULL)) {
|
||||
struct _presence_note_obj_st st;
|
||||
struct _presence_note_obj_st st={0};
|
||||
st.writer = writer;
|
||||
st.ns = NULL;
|
||||
st.err = &err;
|
||||
|
|
@ -1923,12 +1836,11 @@ void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presen
|
|||
if (err >= 0) {
|
||||
err = xmlTextWriterEndDocument(writer);
|
||||
}
|
||||
|
||||
xmlFreeTextWriter(writer);
|
||||
if (err > 0) {
|
||||
/* xmlTextWriterEndDocument returns the size of the content. */
|
||||
*content = ms_strdup((char *)buf->content);
|
||||
}
|
||||
xmlFreeTextWriter(writer);
|
||||
xmlBufferFree(buf);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#ifndef _PRIVATE_H
|
||||
#define _PRIVATE_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "linphonecore.h"
|
||||
|
|
@ -34,6 +35,9 @@ extern "C" {
|
|||
#include "sal/sal.h"
|
||||
#include "sipsetup.h"
|
||||
|
||||
#include <belle-sip/object.h>
|
||||
#include <belle-sip/dict.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
|
@ -63,7 +67,7 @@ extern "C" {
|
|||
#ifdef HAVE_GETTEXT
|
||||
#include <libintl.h>
|
||||
#ifndef _
|
||||
#define _(String) gettext(String)
|
||||
#define _(String) dgettext(GETTEXT_PACKAGE,String)
|
||||
#endif
|
||||
#else
|
||||
#ifndef _
|
||||
|
|
@ -87,11 +91,11 @@ struct _LinphoneCallParams{
|
|||
int down_ptime;
|
||||
int up_ptime;
|
||||
char *record_file;
|
||||
char *session_name;
|
||||
SalCustomHeader *custom_headers;
|
||||
bool_t has_video;
|
||||
bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
|
||||
bool_t in_conference; /*in conference mode */
|
||||
bool_t pad;
|
||||
bool_t low_bandwidth;
|
||||
LinphonePrivacyMask privacy;
|
||||
};
|
||||
|
|
@ -128,6 +132,7 @@ typedef enum _LinphoneChatMessageDir{
|
|||
} LinphoneChatMessageDir;
|
||||
|
||||
struct _LinphoneChatMessage {
|
||||
belle_sip_object_t base;
|
||||
LinphoneChatRoom* chat_room;
|
||||
LinphoneChatMessageDir dir;
|
||||
char* message;
|
||||
|
|
@ -142,38 +147,47 @@ struct _LinphoneChatMessage {
|
|||
LinphoneChatMessageState state;
|
||||
bool_t is_read;
|
||||
unsigned int storage_id;
|
||||
SalOp *op;
|
||||
};
|
||||
|
||||
BELLE_SIP_DECLARE_VPTR(LinphoneChatMessage);
|
||||
|
||||
typedef struct StunCandidate{
|
||||
char addr[64];
|
||||
int port;
|
||||
}StunCandidate;
|
||||
|
||||
|
||||
typedef struct _PortConfig{
|
||||
int rtp_port;
|
||||
int rtcp_port;
|
||||
}PortConfig;
|
||||
|
||||
struct _LinphoneCall
|
||||
{
|
||||
int magic; /*used to distinguish from proxy config*/
|
||||
struct _LinphoneCore *core;
|
||||
SalErrorInfo non_op_error;
|
||||
int af; /*the address family to prefer for RTP path, guessed from signaling path*/
|
||||
LinphoneCallDir dir;
|
||||
SalMediaDescription *biggestdesc; /*media description with all already proposed streams, used to remember the mapping of streams*/
|
||||
SalMediaDescription *localdesc;
|
||||
SalMediaDescription *resultdesc;
|
||||
LinphoneCallDir dir;
|
||||
struct _RtpProfile *audio_profile;
|
||||
struct _RtpProfile *video_profile;
|
||||
struct _LinphoneCallLog *log;
|
||||
SalOp *op;
|
||||
SalOp *ping_op;
|
||||
char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */
|
||||
time_t start_time; /*time at which the call was initiated*/
|
||||
time_t media_start_time; /*time at which it was accepted, media streams established*/
|
||||
LinphoneCallState state;
|
||||
LinphoneCallState prevstate;
|
||||
LinphoneCallState transfer_state; /*idle if no transfer*/
|
||||
LinphoneReason reason;
|
||||
LinphoneProxyConfig *dest_proxy;
|
||||
int refcnt;
|
||||
void * user_pointer;
|
||||
int audio_port;
|
||||
int video_port;
|
||||
PortConfig media_ports[2];
|
||||
MSMediaStreamSessions sessions[2]; /*the rtp, srtp, zrtp contexts for each stream*/
|
||||
StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/
|
||||
struct _AudioStream *audiostream; /**/
|
||||
struct _VideoStream *videostream;
|
||||
|
|
@ -193,29 +207,26 @@ struct _LinphoneCall
|
|||
UpnpSession *upnp_session;
|
||||
#endif //BUILD_UPNP
|
||||
IceSession *ice_session;
|
||||
LinphoneChatMessage* pending_message;
|
||||
int ping_time;
|
||||
unsigned int remote_session_id;
|
||||
unsigned int remote_session_ver;
|
||||
LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/
|
||||
LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */
|
||||
int localdesc_changed;
|
||||
|
||||
int localdesc_changed;/*not a boolean, contains a mask representing changes*/
|
||||
|
||||
bool_t refer_pending;
|
||||
bool_t media_pending;
|
||||
bool_t expect_media_in_ack;
|
||||
bool_t audio_muted;
|
||||
bool_t camera_active;
|
||||
|
||||
bool_t camera_enabled;
|
||||
|
||||
bool_t all_muted; /*this flag is set during early medias*/
|
||||
bool_t playing_ringbacktone;
|
||||
bool_t owns_call_log;
|
||||
bool_t ringing_beep; /* whether this call is ringing through an already existent current call*/
|
||||
|
||||
bool_t videostream_encrypted;
|
||||
bool_t audiostream_encrypted;
|
||||
|
||||
bool_t auth_token_verified;
|
||||
bool_t defer_update;
|
||||
|
||||
|
||||
bool_t was_automatically_paused;
|
||||
bool_t ping_replied;
|
||||
bool_t record_active;
|
||||
|
|
@ -250,20 +261,18 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc);
|
|||
* */
|
||||
const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg);
|
||||
|
||||
|
||||
int linphone_online_status_to_eXosip(LinphoneOnlineStatus os);
|
||||
void linphone_friend_close_subscriptions(LinphoneFriend *lf);
|
||||
void linphone_friend_update_subscribes(LinphoneFriend *fr, LinphoneProxyConfig *cfg, bool_t only_when_registered);
|
||||
void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence);
|
||||
LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op);
|
||||
LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op);
|
||||
MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf);
|
||||
bool_t linphone_core_should_subscribe_friends_only_when_registered(const LinphoneCore *lc);
|
||||
void linphone_core_update_friends_subscriptions(LinphoneCore *lc, LinphoneProxyConfig *cfg, bool_t only_when_registered);
|
||||
|
||||
int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port);
|
||||
int set_lock_file();
|
||||
int get_lock_file();
|
||||
int remove_lock_file();
|
||||
void check_sound_device(LinphoneCore *lc);
|
||||
void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result);
|
||||
|
||||
void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result);
|
||||
bool_t host_has_ipv6_network();
|
||||
bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret);
|
||||
|
||||
|
|
@ -319,6 +328,7 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call);
|
|||
void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
|
||||
void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
|
||||
bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md);
|
||||
bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md);
|
||||
|
||||
void linphone_core_send_initial_subscribes(LinphoneCore *lc);
|
||||
void linphone_core_write_friends_config(LinphoneCore* lc);
|
||||
|
|
@ -337,8 +347,7 @@ void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,Linphon
|
|||
int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len);
|
||||
|
||||
void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *msg);
|
||||
|
||||
void linphone_core_play_tone(LinphoneCore *lc);
|
||||
void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing);
|
||||
|
||||
void linphone_call_init_stats(LinphoneCallStats *stats, int type);
|
||||
void linphone_call_fix_call_parameters(LinphoneCall *call);
|
||||
|
|
@ -363,25 +372,25 @@ void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float
|
|||
void linphone_core_stop_waiting(LinphoneCore *lc);
|
||||
|
||||
int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
|
||||
int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call);
|
||||
int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const LinphoneAddress* destination/* = NULL if to be taken from the call log */);
|
||||
int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call);
|
||||
int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call);
|
||||
int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call);
|
||||
void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call);
|
||||
void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call);
|
||||
bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md);
|
||||
extern SalCallbacks linphone_sal_callbacks;
|
||||
void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg, LinphoneReason error);
|
||||
bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc);
|
||||
|
||||
LinphoneCall * is_a_linphone_call(void *user_pointer);
|
||||
LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer);
|
||||
|
||||
void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description);
|
||||
|
||||
static const int linphone_proxy_config_magic=0x7979;
|
||||
|
||||
/*chat*/
|
||||
/*chat*/
|
||||
void linphone_chat_message_destroy(LinphoneChatMessage* msg);
|
||||
/**/
|
||||
/**/
|
||||
|
||||
struct _LinphoneProxyConfig
|
||||
{
|
||||
|
|
@ -392,6 +401,7 @@ struct _LinphoneProxyConfig
|
|||
char *reg_route;
|
||||
char *realm;
|
||||
char *contact_params;
|
||||
char *contact_uri_params;
|
||||
int expires;
|
||||
SalOp *op;
|
||||
char *type;
|
||||
|
|
@ -408,7 +418,6 @@ struct _LinphoneProxyConfig
|
|||
bool_t pad[3];
|
||||
void* user_data;
|
||||
time_t deletion_date;
|
||||
LinphoneReason error;
|
||||
LinphonePrivacyMask privacy;
|
||||
};
|
||||
|
||||
|
|
@ -420,21 +429,28 @@ struct _LinphoneAuthInfo
|
|||
char *passwd;
|
||||
char *ha1;
|
||||
char *domain;
|
||||
int usecount;
|
||||
time_t last_use_time;
|
||||
bool_t works;
|
||||
};
|
||||
|
||||
typedef enum _LinphoneIsComposingState {
|
||||
LinphoneIsComposingIdle,
|
||||
LinphoneIsComposingActive
|
||||
} LinphoneIsComposingState;
|
||||
|
||||
struct _LinphoneChatRoom{
|
||||
struct _LinphoneCore *lc;
|
||||
char *peer;
|
||||
LinphoneAddress *peer_url;
|
||||
void * user_data;
|
||||
MSList *messages_hist;
|
||||
LinphoneIsComposingState remote_is_composing;
|
||||
LinphoneIsComposingState is_composing;
|
||||
belle_sip_source_t *remote_composing_refresh_timer;
|
||||
belle_sip_source_t *composing_idle_timer;
|
||||
belle_sip_source_t *composing_refresh_timer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct _LinphoneFriend{
|
||||
LinphoneAddress *uri;
|
||||
SalOp *insub;
|
||||
|
|
@ -486,7 +502,7 @@ typedef struct rtp_config
|
|||
int nortp_timeout;
|
||||
int disable_upnp;
|
||||
bool_t rtp_no_xmit_on_audio_mute;
|
||||
/* stop rtp xmit when audio muted */
|
||||
/* stop rtp xmit when audio muted */
|
||||
bool_t audio_adaptive_jitt_comp_enabled;
|
||||
bool_t video_adaptive_jitt_comp_enabled;
|
||||
bool_t pad;
|
||||
|
|
@ -574,6 +590,20 @@ struct _LinphoneConference{
|
|||
bool_t local_muted;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _LinphoneToneDescription{
|
||||
LinphoneReason reason;
|
||||
LinphoneToneID toneid;
|
||||
char *audiofile;
|
||||
}LinphoneToneDescription;
|
||||
|
||||
LinphoneToneDescription * linphone_tone_description_new(LinphoneReason reason, LinphoneToneID id, const char *audiofile);
|
||||
void linphone_tone_description_destroy(LinphoneToneDescription *obj);
|
||||
LinphoneToneDescription *linphone_core_get_call_error_tone(const LinphoneCore *lc, LinphoneReason reason);
|
||||
void linphone_core_play_call_error_tone(LinphoneCore *lc, LinphoneReason reason);
|
||||
void _linphone_core_set_tone(LinphoneCore *lc, LinphoneReason reason, LinphoneToneID id, const char *audiofile);
|
||||
const char *linphone_core_get_tone_file(const LinphoneCore *lc, LinphoneToneID id);
|
||||
int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params);
|
||||
typedef struct _LinphoneConference LinphoneConference;
|
||||
|
||||
struct _LinphoneCore
|
||||
|
|
@ -632,17 +662,17 @@ struct _LinphoneCore
|
|||
bool_t apply_nat_settings;
|
||||
bool_t initial_subscribes_sent;
|
||||
bool_t bl_refresh;
|
||||
|
||||
|
||||
bool_t preview_finished;
|
||||
bool_t auto_net_state_mon;
|
||||
bool_t network_reachable;
|
||||
bool_t use_preview_window;
|
||||
|
||||
time_t network_last_check;
|
||||
bool_t network_last_status;
|
||||
|
||||
time_t network_last_check;
|
||||
|
||||
bool_t network_last_status;
|
||||
bool_t ringstream_autorelease;
|
||||
bool_t pad[3];
|
||||
bool_t pad[2];
|
||||
int device_rotation;
|
||||
int max_calls;
|
||||
LinphoneTunnel *tunnel;
|
||||
|
|
@ -655,6 +685,10 @@ struct _LinphoneCore
|
|||
#ifdef BUILD_UPNP
|
||||
UpnpContext *upnp;
|
||||
#endif //BUILD_UPNP
|
||||
belle_http_provider_t *http_provider;
|
||||
belle_tls_verify_policy_t *http_verify_policy;
|
||||
MSList *tones;
|
||||
LinphoneReason chat_deny_code;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -662,14 +696,15 @@ struct _LinphoneEvent{
|
|||
LinphoneSubscriptionDir dir;
|
||||
LinphoneCore *lc;
|
||||
SalOp *op;
|
||||
SalCustomHeader *send_custom_headers;
|
||||
LinphoneSubscriptionState subscription_state;
|
||||
LinphonePublishState publish_state;
|
||||
LinphoneReason reason;
|
||||
void *userdata;
|
||||
int refcnt;
|
||||
char *name;
|
||||
LinphoneAddress *from;
|
||||
LinphoneAddress *resource_addr;
|
||||
int expires;
|
||||
bool_t terminating;
|
||||
};
|
||||
|
||||
|
|
@ -691,7 +726,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
|
|||
|
||||
bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit);
|
||||
|
||||
#define linphone_core_ready(lc) ((lc)->state!=LinphoneGlobalStartup)
|
||||
#define linphone_core_ready(lc) ((lc)->state==LinphoneGlobalOn || (lc)->state==LinphoneGlobalShutdown)
|
||||
void _linphone_core_configure_resolver();
|
||||
|
||||
struct _EcCalibrator{
|
||||
|
|
@ -762,32 +797,78 @@ void linphone_chat_message_store_state(LinphoneChatMessage *msg);
|
|||
void linphone_core_message_storage_init(LinphoneCore *lc);
|
||||
void linphone_core_message_storage_close(LinphoneCore *lc);
|
||||
|
||||
typedef enum _LinphoneToneID{
|
||||
LinphoneToneBusy,
|
||||
LinphoneToneCallWaiting,
|
||||
LinphoneToneCallOnHold,
|
||||
LinphoneToneCallFailed
|
||||
}LinphoneToneID;
|
||||
void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id);
|
||||
bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc);
|
||||
const char *linphone_core_create_uuid(LinphoneCore *lc);
|
||||
void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact);
|
||||
void linphone_call_create_op(LinphoneCall *call);
|
||||
int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer);
|
||||
void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body);
|
||||
LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref);
|
||||
SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc);
|
||||
SalReason linphone_reason_to_sal(LinphoneReason reason);
|
||||
LinphoneReason linphone_reason_from_sal(SalReason reason);
|
||||
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name);
|
||||
LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, int expires);
|
||||
LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name);
|
||||
void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state);
|
||||
void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state);
|
||||
void linphone_event_set_reason(LinphoneEvent *lev, LinphoneReason reason);
|
||||
LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss);
|
||||
const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref);
|
||||
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc);
|
||||
|
||||
void linphone_call_stream_stats_hack(MediaStream* stream, LinphoneCallStats *stats, OrtpEvent *ev);
|
||||
|
||||
/*****************************************************************************
|
||||
* REMOTE PROVISIONING FUNCTIONS *
|
||||
****************************************************************************/
|
||||
|
||||
void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message);
|
||||
int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* XML UTILITY FUNCTIONS *
|
||||
****************************************************************************/
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/xmlwriter.h>
|
||||
#include <libxml/xpath.h>
|
||||
#include <libxml/xpathInternals.h>
|
||||
|
||||
#define XMLPARSING_BUFFER_LEN 2048
|
||||
#define MAX_XPATH_LENGTH 256
|
||||
|
||||
typedef struct _xmlparsing_context {
|
||||
xmlDoc *doc;
|
||||
xmlXPathContextPtr xpath_ctx;
|
||||
char errorBuffer[XMLPARSING_BUFFER_LEN];
|
||||
char warningBuffer[XMLPARSING_BUFFER_LEN];
|
||||
} xmlparsing_context_t;
|
||||
|
||||
xmlparsing_context_t * linphone_xmlparsing_context_new(void);
|
||||
void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx);
|
||||
void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...);
|
||||
int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx);
|
||||
char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
|
||||
void linphone_free_xml_text_content(const char *text);
|
||||
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression);
|
||||
|
||||
static inline const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){
|
||||
if (op==NULL) return (LinphoneErrorInfo*)sal_error_info_none();
|
||||
return (const LinphoneErrorInfo*)sal_op_get_error_info(op);
|
||||
}
|
||||
|
||||
/** Belle Sip-based objects need unique ids
|
||||
*/
|
||||
|
||||
BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000)
|
||||
BELLE_SIP_TYPE_ID(LinphoneContactSearch),
|
||||
BELLE_SIP_TYPE_ID(LinphoneContactProvider),
|
||||
BELLE_SIP_TYPE_ID(LinphoneLDAPContactProvider),
|
||||
BELLE_SIP_TYPE_ID(LinphoneLDAPContactSearch),
|
||||
BELLE_SIP_TYPE_ID(LinphoneChatMessage)
|
||||
BELLE_SIP_DECLARE_TYPES_END
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
165
coreapi/proxy.c
165
coreapi/proxy.c
|
|
@ -41,13 +41,26 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){
|
|||
lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL));
|
||||
}
|
||||
|
||||
static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj){
|
||||
memset(obj,0,sizeof(LinphoneProxyConfig));
|
||||
obj->magic=linphone_proxy_config_magic;
|
||||
obj->expires=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"reg_expires",3600);
|
||||
obj->dial_prefix=ms_strdup(LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",'\0'));
|
||||
obj->dial_escape_plus=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"dial_escape_plus",0);
|
||||
obj->privacy=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"privacy",LinphonePrivacyDefault);
|
||||
static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *obj) {
|
||||
const char *dial_prefix = lc ? lp_config_get_default_string(lc->config,"proxy","dial_prefix",NULL) : NULL;
|
||||
const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL;
|
||||
const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL;
|
||||
const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL;
|
||||
const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL;
|
||||
const char *contact_uri_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_uri_parameters", NULL) : NULL;
|
||||
|
||||
memset(obj, 0, sizeof(LinphoneProxyConfig));
|
||||
obj->magic = linphone_proxy_config_magic;
|
||||
obj->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600;
|
||||
obj->reg_sendregister = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_sendregister", 0) : 0;
|
||||
obj->dial_prefix = dial_prefix ? ms_strdup(dial_prefix) : NULL;
|
||||
obj->dial_escape_plus = lc ? lp_config_get_default_int(lc->config, "proxy", "dial_escape_plus", 0) : 0;
|
||||
obj->privacy = lc ? lp_config_get_default_int(lc->config, "proxy", "privacy", LinphonePrivacyDefault) : LinphonePrivacyDefault;
|
||||
obj->reg_identity = identity ? ms_strdup(identity) : NULL;
|
||||
obj->reg_proxy = proxy ? ms_strdup(proxy) : NULL;
|
||||
obj->reg_route = route ? ms_strdup(route) : NULL;
|
||||
obj->contact_params = contact_params ? ms_strdup(contact_params) : NULL;
|
||||
obj->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -62,6 +75,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj
|
|||
LinphoneProxyConfig *linphone_proxy_config_new() {
|
||||
return linphone_core_create_proxy_config(NULL);
|
||||
}
|
||||
|
||||
LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) {
|
||||
LinphoneProxyConfig *obj=NULL;
|
||||
obj=ms_new(LinphoneProxyConfig,1);
|
||||
|
|
@ -69,8 +83,6 @@ LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) {
|
|||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Destroys a proxy config.
|
||||
*
|
||||
|
|
@ -88,6 +100,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){
|
|||
if (obj->op) sal_op_release(obj->op);
|
||||
if (obj->publish_op) sal_op_release(obj->publish_op);
|
||||
if (obj->contact_params) ms_free(obj->contact_params);
|
||||
if (obj->contact_uri_params) ms_free(obj->contact_uri_params);
|
||||
ms_free(obj);
|
||||
}
|
||||
|
||||
|
|
@ -257,6 +270,9 @@ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){
|
|||
if (obj->state == LinphoneRegistrationOk
|
||||
|| obj->state == LinphoneRegistrationProgress) {
|
||||
sal_unregister(obj->op);
|
||||
} else {
|
||||
/*stop refresher*/
|
||||
if (obj->op) sal_op_stop_refreshing(obj->op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -280,69 +296,38 @@ void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj){
|
|||
LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){
|
||||
LinphoneAddress *ret=NULL;
|
||||
LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy);
|
||||
|
||||
const char *host;
|
||||
|
||||
if (proxy==NULL) return NULL;
|
||||
host=linphone_address_get_domain (proxy);
|
||||
host=linphone_address_get_domain(proxy);
|
||||
if (host!=NULL){
|
||||
int localport = -1;
|
||||
const char *localip = NULL;
|
||||
char *tmp;
|
||||
char *tmp2;
|
||||
LinphoneAddress *identity;
|
||||
LinphoneAddress *contact;
|
||||
LinphoneAddress *contact=linphone_address_new(obj->reg_identity);
|
||||
|
||||
linphone_address_clean(contact);
|
||||
|
||||
if (obj->contact_params) {
|
||||
// We want to add a list of contacts params to the linphone address
|
||||
// We remove the display name in the identity (if present) to prevent a failure in the parsing of the address due to the quotes
|
||||
identity = linphone_address_new(obj->reg_identity);
|
||||
if (identity) {
|
||||
tmp2 = linphone_address_as_string_uri_only(identity);
|
||||
tmp = ms_strdup_printf("%s;%s", tmp2, obj->contact_params);
|
||||
linphone_address_destroy(identity);
|
||||
ms_free(tmp2);
|
||||
} else {
|
||||
tmp = ms_strdup_printf("%s;%s", obj->reg_identity, obj->contact_params);
|
||||
}
|
||||
sal_address_set_params(contact,obj->contact_params);
|
||||
}
|
||||
else {
|
||||
tmp = strdup(obj->reg_identity);
|
||||
if (obj->contact_uri_params){
|
||||
sal_address_set_uri_params(contact,obj->contact_uri_params);
|
||||
}
|
||||
|
||||
contact = linphone_address_new(tmp);
|
||||
if (!contact) {
|
||||
ms_error("No valid contact_params for [%s]",linphone_address_get_domain(proxy));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef BUILD_UPNP
|
||||
if (obj->lc->upnp != NULL && linphone_core_get_firewall_policy(obj->lc)==LinphonePolicyUseUpnp &&
|
||||
linphone_upnp_context_get_state(obj->lc->upnp) == LinphoneUpnpStateOk) {
|
||||
LCSipTransports tr;
|
||||
localip = linphone_upnp_context_get_external_ipaddress(obj->lc->upnp);
|
||||
localport = linphone_upnp_context_get_external_port(obj->lc->upnp);
|
||||
linphone_core_get_sip_transports(obj->lc,&tr);
|
||||
if (tr.udp_port <= 0) {
|
||||
if (tr.tcp_port>0) {
|
||||
sal_address_set_param(contact,"transport","tcp");
|
||||
} else if (tr.tls_port>0) {
|
||||
sal_address_set_param(contact,"transport","tls");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif //BUILD_UPNP
|
||||
|
||||
|
||||
linphone_address_set_port(contact,localport);
|
||||
linphone_address_set_domain(contact,localip);
|
||||
linphone_address_set_display_name(contact,NULL);
|
||||
|
||||
ret=contact;
|
||||
|
||||
linphone_address_destroy (proxy);
|
||||
ms_free(tmp);
|
||||
}
|
||||
linphone_address_destroy(proxy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -351,23 +336,16 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
|
|||
if (obj->reg_sendregister){
|
||||
LinphoneAddress* proxy=linphone_address_new(obj->reg_proxy);
|
||||
char* proxy_string;
|
||||
#ifndef USE_BELLESIP
|
||||
char *contact;
|
||||
#else
|
||||
LinphoneAddress *contact;
|
||||
#endif
|
||||
|
||||
proxy_string=linphone_address_as_string_uri_only(proxy);
|
||||
linphone_address_destroy(proxy);
|
||||
if (obj->op)
|
||||
sal_op_release(obj->op);
|
||||
obj->op=sal_op_new(obj->lc->sal);
|
||||
if ((contact=guess_contact_for_register(obj))) {
|
||||
sal_op_set_contact(obj->op,contact);
|
||||
#ifndef USE_BELLESIP
|
||||
ms_free(contact);
|
||||
#else
|
||||
sal_op_set_contact_address(obj->op,contact);
|
||||
linphone_address_destroy(contact);
|
||||
#endif
|
||||
}
|
||||
sal_op_set_user_pointer(obj->op,obj);
|
||||
if (sal_register(obj->op,proxy_string,obj->reg_identity,obj->expires)==0) {
|
||||
|
|
@ -376,6 +354,9 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
|
|||
linphone_proxy_config_set_state(obj,LinphoneRegistrationFailed,"Registration failed");
|
||||
}
|
||||
ms_free(proxy_string);
|
||||
} else {
|
||||
/*stop refresher, just in case*/
|
||||
if (obj->op) sal_op_stop_refreshing(obj->op);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -384,7 +365,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
|
|||
* This is useful if for example you resuming from suspend, thus IP address may have changed.
|
||||
**/
|
||||
void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj){
|
||||
if (obj->reg_sendregister && obj->op){
|
||||
if (obj->reg_sendregister && obj->op && obj->state!=LinphoneRegistrationProgress){
|
||||
if (sal_register_refresh(obj->op,obj->expires) == 0) {
|
||||
linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress, "Refresh registration");
|
||||
}
|
||||
|
|
@ -852,7 +833,7 @@ int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePrese
|
|||
sal_op_set_to(proxy->publish_op,linphone_proxy_config_get_identity(proxy));
|
||||
if (lp_config_get_int(proxy->lc->config,"sip","publish_msg_with_contact",0)){
|
||||
SalAddress *addr=sal_address_new(linphone_proxy_config_get_identity(proxy));
|
||||
sal_op_set_contact(proxy->publish_op,addr);
|
||||
sal_op_set_contact_address(proxy->publish_op,addr);
|
||||
sal_address_unref(addr);
|
||||
}
|
||||
}
|
||||
|
|
@ -911,7 +892,7 @@ bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj){
|
|||
* @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else"
|
||||
*
|
||||
* The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id.
|
||||
* As an example, the contact address in the SIP register sent will look like <sip:joe@15.128.128.93:50421;apple-push-id=43143-DFE23F-2323-FA2232>.
|
||||
* As an example, the contact address in the SIP register sent will look like <sip:joe@15.128.128.93:50421>;apple-push-id=43143-DFE23F-2323-FA2232.
|
||||
**/
|
||||
void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params){
|
||||
if (obj->contact_params) {
|
||||
|
|
@ -923,6 +904,24 @@ void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, cons
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set optional contact parameters that will be added to the contact information sent in the registration, inside the URI.
|
||||
* @param obj the proxy config object
|
||||
* @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else"
|
||||
*
|
||||
* The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id.
|
||||
* As an example, the contact address in the SIP register sent will look like <sip:joe@15.128.128.93:50421;apple-push-id=43143-DFE23F-2323-FA2232>.
|
||||
**/
|
||||
void linphone_proxy_config_set_contact_uri_parameters(LinphoneProxyConfig *obj, const char *contact_uri_params){
|
||||
if (obj->contact_uri_params) {
|
||||
ms_free(obj->contact_uri_params);
|
||||
obj->contact_uri_params=NULL;
|
||||
}
|
||||
if (contact_uri_params){
|
||||
obj->contact_uri_params=ms_strdup(contact_uri_params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns previously set contact parameters.
|
||||
**/
|
||||
|
|
@ -930,6 +929,13 @@ const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConf
|
|||
return obj->contact_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns previously set contact URI parameters.
|
||||
**/
|
||||
const char *linphone_proxy_config_get_contact_uri_parameters(const LinphoneProxyConfig *obj){
|
||||
return obj->contact_uri_params;
|
||||
}
|
||||
|
||||
struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj){
|
||||
return obj->lc;
|
||||
}
|
||||
|
|
@ -1059,6 +1065,9 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC
|
|||
if (obj->contact_params!=NULL){
|
||||
lp_config_set_string(config,key,"contact_parameters",obj->contact_params);
|
||||
}
|
||||
if (obj->contact_uri_params!=NULL){
|
||||
lp_config_set_string(config,key,"contact_uri_parameters",obj->contact_uri_params);
|
||||
}
|
||||
lp_config_set_int(config,key,"reg_expires",obj->expires);
|
||||
lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister);
|
||||
lp_config_set_int(config,key,"publish",obj->publish);
|
||||
|
|
@ -1096,19 +1105,21 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config
|
|||
|
||||
linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL));
|
||||
|
||||
linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",LP_CONFIG_DEFAULT_INT(config,"reg_expires",600)));
|
||||
linphone_proxy_config_set_contact_uri_parameters(cfg,lp_config_get_string(config,key,"contact_uri_parameters",NULL));
|
||||
|
||||
linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",lp_config_get_default_int(config,"proxy","reg_expires",600)));
|
||||
linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0));
|
||||
|
||||
linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0));
|
||||
|
||||
linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",LP_CONFIG_DEFAULT_INT(config,"dial_escape_plus",0)));
|
||||
linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",LP_CONFIG_DEFAULT_STRING(config,"dial_prefix",NULL)));
|
||||
linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",lp_config_get_default_int(config,"proxy","dial_escape_plus",0)));
|
||||
linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",lp_config_get_default_string(config,"proxy","dial_prefix",NULL)));
|
||||
|
||||
tmp=lp_config_get_string(config,key,"type",NULL);
|
||||
if (tmp!=NULL && strlen(tmp)>0)
|
||||
linphone_proxy_config_set_sip_setup(cfg,tmp);
|
||||
|
||||
linphone_proxy_config_set_privacy(cfg,lp_config_get_int(config,key,"privacy",LP_CONFIG_DEFAULT_INT(config,"privacy",LinphonePrivacyDefault)));
|
||||
linphone_proxy_config_set_privacy(cfg,lp_config_get_int(config,key,"privacy",lp_config_get_default_int(config,"proxy","privacy",LinphonePrivacyDefault)));
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
|
@ -1127,7 +1138,7 @@ static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){
|
|||
}
|
||||
caps=sip_setup_context_get_capabilities(ssc);
|
||||
if (caps & SIP_SETUP_CAP_ACCOUNT_MANAGER){
|
||||
if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL)!=0){
|
||||
if (sip_setup_context_login_account(ssc,cfg->reg_identity,NULL,NULL)!=0){
|
||||
if (lc->vtable.display_warning){
|
||||
char *tmp=ms_strdup_printf(_("Could not login as %s"),cfg->reg_identity);
|
||||
lc->vtable.display_warning(lc,tmp);
|
||||
|
|
@ -1314,14 +1325,22 @@ void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) {
|
|||
|
||||
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){
|
||||
LinphoneCore *lc=cfg->lc;
|
||||
|
||||
|
||||
ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg,
|
||||
bool_t update_friends=FALSE;
|
||||
|
||||
if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/
|
||||
ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg,
|
||||
linphone_proxy_config_get_identity(cfg),
|
||||
linphone_registration_state_to_string(cfg->state),
|
||||
linphone_registration_state_to_string(state));
|
||||
if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/
|
||||
if (linphone_core_should_subscribe_friends_only_when_registered(lc)){
|
||||
update_friends=(state==LinphoneRegistrationOk && cfg->state!=LinphoneRegistrationOk)
|
||||
|| (state!=LinphoneRegistrationOk && cfg->state==LinphoneRegistrationOk);
|
||||
}
|
||||
cfg->state=state;
|
||||
|
||||
if (update_friends){
|
||||
linphone_core_update_friends_subscriptions(lc,cfg,TRUE);
|
||||
}
|
||||
if (lc && lc->vtable.registration_state_changed){
|
||||
lc->vtable.registration_state_changed(lc,cfg,state,message);
|
||||
}
|
||||
|
|
@ -1356,11 +1375,11 @@ LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyCon
|
|||
}
|
||||
|
||||
LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg) {
|
||||
return cfg->error;
|
||||
return linphone_error_info_get_reason(linphone_proxy_config_get_error_info(cfg));
|
||||
}
|
||||
|
||||
void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason error) {
|
||||
cfg->error = error;
|
||||
const LinphoneErrorInfo *linphone_proxy_config_get_error_info(const LinphoneProxyConfig *cfg){
|
||||
return linphone_error_info_from_sal_op(cfg->op);
|
||||
}
|
||||
|
||||
const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) {
|
||||
|
|
|
|||
147
coreapi/remote_provisioning.c
Normal file
147
coreapi/remote_provisioning.c
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
remote_provisioning.c
|
||||
Copyright (C) 2010 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include "private.h"
|
||||
#include "xml2lpc.h"
|
||||
|
||||
#define XML2LPC_CALLBACK_BUFFER_SIZE 1024
|
||||
|
||||
static void xml2lpc_callback(void *ctx, xml2lpc_log_level level, const char *fmt, va_list list) {
|
||||
char buffer[XML2LPC_CALLBACK_BUFFER_SIZE];
|
||||
vsnprintf(buffer, XML2LPC_CALLBACK_BUFFER_SIZE, fmt, list);
|
||||
|
||||
if (level == XML2LPC_ERROR)
|
||||
ms_error("%s", buffer);
|
||||
else if (level == XML2LPC_WARNING)
|
||||
ms_warning("%s", buffer);
|
||||
/*else
|
||||
ms_message("%s", buffer); // Don't log debug messages */
|
||||
}
|
||||
|
||||
static void linphone_remote_provisioning_apply(LinphoneCore *lc, const char *xml) {
|
||||
xml2lpc_context *context = xml2lpc_context_new(xml2lpc_callback, lc);
|
||||
int result = xml2lpc_set_xml_string(context, xml);
|
||||
if (result == 0) {
|
||||
result = xml2lpc_convert(context, linphone_core_get_config(lc));
|
||||
if (result == 0) {
|
||||
lp_config_sync(linphone_core_get_config(lc));
|
||||
xml2lpc_context_destroy(context);
|
||||
linphone_configuring_terminated(lc, LinphoneConfiguringSuccessful, NULL);
|
||||
} else {
|
||||
xml2lpc_context_destroy(context);
|
||||
linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "xml to lpc failed");
|
||||
}
|
||||
} else {
|
||||
xml2lpc_context_destroy(context);
|
||||
linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "invalid xml");
|
||||
}
|
||||
}
|
||||
|
||||
static int linphone_remote_provisioning_load_file( LinphoneCore* lc, const char* file_path){
|
||||
int status = -1;
|
||||
FILE* f = fopen(file_path, "r");
|
||||
|
||||
if( f ){
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
char* provisioning = ms_malloc(fsize + 1);
|
||||
provisioning[fsize]='\0';
|
||||
if (fread(provisioning, fsize, 1, f)==0){
|
||||
ms_error("Could not read xml provisioning file from %s",file_path);
|
||||
status=-1;
|
||||
}else{
|
||||
linphone_remote_provisioning_apply(lc, provisioning);
|
||||
status = 0;
|
||||
}
|
||||
ms_free(provisioning);
|
||||
fclose(f);
|
||||
} else {
|
||||
ms_error("Couldn't open file %s for provisioning", file_path);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void belle_request_process_response_event(void *ctx, const belle_http_response_event_t *event) {
|
||||
LinphoneCore *lc = (LinphoneCore *)ctx;
|
||||
belle_sip_message_t *body = BELLE_SIP_MESSAGE(event->response);
|
||||
const char *message = belle_sip_message_get_body(body);
|
||||
|
||||
if (belle_http_response_get_status_code(event->response) == 200) {
|
||||
linphone_remote_provisioning_apply(lc, message);
|
||||
} else {
|
||||
linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http error");
|
||||
}
|
||||
}
|
||||
|
||||
static void belle_request_process_io_error(void *ctx, const belle_sip_io_error_event_t *event) {
|
||||
LinphoneCore *lc = (LinphoneCore *)ctx;
|
||||
linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http io error");
|
||||
}
|
||||
|
||||
static void belle_request_process_timeout(void *ctx, const belle_sip_timeout_event_t *event) {
|
||||
LinphoneCore *lc = (LinphoneCore *)ctx;
|
||||
linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http timeout");
|
||||
}
|
||||
|
||||
static void belle_request_process_auth_requested(void *ctx, belle_sip_auth_event_t *event) {
|
||||
LinphoneCore *lc = (LinphoneCore *)ctx;
|
||||
linphone_configuring_terminated(lc, LinphoneConfiguringFailed, "http auth requested");
|
||||
}
|
||||
|
||||
int linphone_remote_provisioning_download_and_apply(LinphoneCore *lc, const char *remote_provisioning_uri) {
|
||||
const char* file_path = strstr(remote_provisioning_uri, "file://");
|
||||
|
||||
if( file_path == remote_provisioning_uri ){
|
||||
// We allow for 'local remote-provisioning' in case the file is to be opened from the hard drive
|
||||
file_path += strlen("file://");
|
||||
return linphone_remote_provisioning_load_file(lc, file_path);
|
||||
} else {
|
||||
belle_generic_uri_t *uri=belle_generic_uri_parse(remote_provisioning_uri);
|
||||
belle_http_request_listener_callbacks_t belle_request_listener = {
|
||||
belle_request_process_response_event,
|
||||
belle_request_process_io_error,
|
||||
belle_request_process_timeout,
|
||||
belle_request_process_auth_requested
|
||||
};
|
||||
belle_http_request_listener_t *listener = belle_http_request_listener_create_from_callbacks(&belle_request_listener, lc);
|
||||
belle_http_request_t *request;
|
||||
|
||||
if (uri==NULL) {
|
||||
belle_sip_error("Invalid provisioning URI [%s]",remote_provisioning_uri);
|
||||
return -1;
|
||||
}
|
||||
request=belle_http_request_create("GET",uri, NULL);
|
||||
belle_http_provider_send_request(lc->http_provider, request, listener);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_core_set_provisioning_uri(LinphoneCore *lc, const char *uri) {
|
||||
lp_config_set_string(lc->config,"misc","config-uri",uri);
|
||||
}
|
||||
|
||||
const char*linphone_core_get_provisioning_uri(const LinphoneCore *lc){
|
||||
return lp_config_get_string(lc->config,"misc","config-uri",NULL);
|
||||
}
|
||||
|
||||
bool_t linphone_core_is_provisioning_transient(LinphoneCore *lc) {
|
||||
return lp_config_get_int(lc->config, "misc", "transient_provisioning", 0) == 1;
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "config.h"
|
||||
#endif
|
||||
#include "sal/sal.h"
|
||||
#include "bellesip_sal/sal_impl.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
|
@ -68,8 +69,9 @@ static void sal_media_description_destroy(SalMediaDescription *md){
|
|||
ms_free(md);
|
||||
}
|
||||
|
||||
void sal_media_description_ref(SalMediaDescription *md){
|
||||
SalMediaDescription * sal_media_description_ref(SalMediaDescription *md){
|
||||
md->refcount++;
|
||||
return md;
|
||||
}
|
||||
|
||||
void sal_media_description_unref(SalMediaDescription *md){
|
||||
|
|
@ -251,7 +253,6 @@ static void assign_string(char **str, const char *arg){
|
|||
*str=ms_strdup(arg);
|
||||
}
|
||||
|
||||
#ifdef USE_BELLESIP
|
||||
void sal_op_set_contact_address(SalOp *op, const SalAddress *address){
|
||||
if (((SalOpBase*)op)->contact_address) sal_address_destroy(((SalOpBase*)op)->contact_address);
|
||||
((SalOpBase*)op)->contact_address=address?sal_address_clone(address):NULL;
|
||||
|
|
@ -259,7 +260,12 @@ void sal_op_set_contact_address(SalOp *op, const SalAddress *address){
|
|||
const SalAddress* sal_op_get_contact_address(const SalOp *op) {
|
||||
return ((SalOpBase*)op)->contact_address;
|
||||
}
|
||||
#endif
|
||||
|
||||
const SalAddress*sal_op_get_remote_contact_address(const SalOp* op)
|
||||
{
|
||||
return ((SalOpBase*)op)->remote_contact_address;
|
||||
}
|
||||
|
||||
#define SET_PARAM(op,name) \
|
||||
char* name##_string=NULL; \
|
||||
assign_address(&((SalOpBase*)op)->name##_address,name); \
|
||||
|
|
@ -269,14 +275,7 @@ const SalAddress* sal_op_get_contact_address(const SalOp *op) {
|
|||
assign_string(&((SalOpBase*)op)->name,name##_string); \
|
||||
if(name##_string) ms_free(name##_string);
|
||||
|
||||
#ifndef USE_BELLESIP
|
||||
void sal_op_set_contact(SalOp *op, const char *contact){
|
||||
assign_string(&((SalOpBase*)op)->contact,contact);
|
||||
}
|
||||
const char *sal_op_get_contact(const SalOp *op){
|
||||
return ((SalOpBase*)op)->contact;
|
||||
}
|
||||
#endif
|
||||
|
||||
void sal_op_set_route(SalOp *op, const char *route){
|
||||
char* route_string=(void *)0;
|
||||
SalOpBase* op_base = (SalOpBase*)op;
|
||||
|
|
@ -382,9 +381,10 @@ void __sal_op_set_network_origin(SalOp *op, const char *origin){
|
|||
SET_PARAM(op,origin);
|
||||
}
|
||||
|
||||
void __sal_op_set_remote_contact(SalOp *op, const char *ct){
|
||||
assign_string(&((SalOpBase*)op)->remote_contact,ct);
|
||||
void __sal_op_set_remote_contact(SalOp *op, const char* remote_contact){
|
||||
SET_PARAM(op,remote_contact);
|
||||
}
|
||||
|
||||
void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin){
|
||||
char* address_string=sal_address_as_string(origin); /*can probably be optimized*/
|
||||
__sal_op_set_network_origin(op,address_string);
|
||||
|
|
@ -424,16 +424,9 @@ void __sal_op_free(SalOp *op){
|
|||
ms_free(b->route);
|
||||
b->route=NULL;
|
||||
}
|
||||
#ifndef USE_BELLESIP
|
||||
if (b->contact) {
|
||||
ms_free(b->contact);
|
||||
b->contact=NULL;
|
||||
}
|
||||
#else
|
||||
if (b->contact_address) {
|
||||
sal_address_destroy(b->contact_address);
|
||||
}
|
||||
#endif
|
||||
if (b->origin){
|
||||
ms_free(b->origin);
|
||||
b->origin=NULL;
|
||||
|
|
@ -446,6 +439,9 @@ void __sal_op_free(SalOp *op){
|
|||
ms_free(b->remote_contact);
|
||||
b->remote_contact=NULL;
|
||||
}
|
||||
if (b->remote_contact_address){
|
||||
sal_address_destroy(b->remote_contact_address);
|
||||
}
|
||||
if (b->local_media)
|
||||
sal_media_description_unref(b->local_media);
|
||||
if (b->remote_media)
|
||||
|
|
@ -502,6 +498,11 @@ const char* sal_stream_type_to_string(SalStreamType type) {
|
|||
}
|
||||
}
|
||||
|
||||
const char *sal_stream_description_get_type_as_string(const SalStreamDescription *desc){
|
||||
if (desc->type==SalOther) return desc->typeother;
|
||||
else return sal_stream_type_to_string(desc->type);
|
||||
}
|
||||
|
||||
const char* sal_media_proto_to_string(SalMediaProto type) {
|
||||
switch (type) {
|
||||
case SalProtoRtpAvp:return "RTP/AVP";
|
||||
|
|
@ -510,6 +511,11 @@ const char* sal_media_proto_to_string(SalMediaProto type) {
|
|||
}
|
||||
}
|
||||
|
||||
const char *sal_stream_description_get_proto_as_string(const SalStreamDescription *desc){
|
||||
if (desc->proto==SalProtoOther) return desc->proto_other;
|
||||
else return sal_media_proto_to_string(desc->proto);
|
||||
}
|
||||
|
||||
|
||||
const char* sal_stream_dir_to_string(SalStreamDir type) {
|
||||
switch (type) {
|
||||
|
|
@ -530,7 +536,7 @@ const char* sal_reason_to_string(const SalReason reason) {
|
|||
case SalReasonTemporarilyUnavailable: return "SalReasonTemporarilyUnavailable";
|
||||
case SalReasonNotFound: return "SalReasonNotFound";
|
||||
case SalReasonDoNotDisturb: return "SalReasonDoNotDisturb";
|
||||
case SalReasonMedia: return "SalReasonMedia";
|
||||
case SalReasonUnsupportedContent: return "SalReasonUnsupportedContent";
|
||||
case SalReasonForbidden: return "SalReasonForbidden";
|
||||
case SalReasonUnknown: return "SalReasonUnknown";
|
||||
case SalReasonServiceUnavailable: return "SalReasonServiceUnavailable";
|
||||
|
|
@ -625,5 +631,7 @@ int sal_body_has_type(const SalBody *body, const char *type, const char *subtype
|
|||
&& strcmp(body->subtype,subtype)==0;
|
||||
}
|
||||
|
||||
|
||||
belle_sip_stack_t *sal_get_belle_sip_stack(Sal *sal) {
|
||||
return sal->stack;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ static void guess_display_name(LinphoneAddress *from){
|
|||
ms_free(dn);
|
||||
}
|
||||
|
||||
static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char *passwd){
|
||||
static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid){
|
||||
LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx);
|
||||
LinphoneCore *lc=linphone_proxy_config_get_core(cfg);
|
||||
LinphoneAuthInfo *auth;
|
||||
|
|
@ -66,7 +66,8 @@ static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char
|
|||
tmp=linphone_address_as_string(parsed_uri);
|
||||
linphone_proxy_config_set_identity(cfg,tmp);
|
||||
if (passwd ) {
|
||||
auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL,NULL);
|
||||
auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),userid,passwd,NULL,NULL,
|
||||
linphone_address_get_domain(parsed_uri));
|
||||
linphone_core_add_auth_info(lc,auth);
|
||||
}
|
||||
linphone_proxy_config_enable_register(cfg,TRUE);
|
||||
|
|
@ -79,6 +80,7 @@ static int sip_login_do_login(SipSetupContext * ctx, const char *uri, const char
|
|||
|
||||
static int sip_login_do_logout(SipSetupContext * ctx){
|
||||
LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx);
|
||||
linphone_proxy_config_edit(cfg);
|
||||
linphone_proxy_config_enable_register(cfg,FALSE);
|
||||
linphone_proxy_config_done(cfg);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ int sip_setup_context_account_validated(SipSetupContext *ctx, const char *uri){
|
|||
return -1;
|
||||
}
|
||||
|
||||
int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd){
|
||||
int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid){
|
||||
LinphoneAddress *from=linphone_address_new(uri);
|
||||
if (from==NULL) {
|
||||
ms_warning("Fail to parse %s",uri);
|
||||
|
|
@ -156,7 +156,7 @@ int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, cons
|
|||
strncpy(ctx->username,linphone_address_get_username(from),sizeof(ctx->username));
|
||||
linphone_address_destroy(from);
|
||||
if (ctx->funcs->login_account)
|
||||
return ctx->funcs->login_account(ctx,uri,passwd);
|
||||
return ctx->funcs->login_account(ctx,uri,passwd,userid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ struct _SipSetup{
|
|||
void (*uninit_instance)(SipSetupContext *ctx);
|
||||
int (*account_exists)(SipSetupContext *ctx, const char *uri);
|
||||
int (*create_account)(SipSetupContext *ctx, const char *uri, const char *passwd, const char *email, int suscribe);
|
||||
int (*login_account)(SipSetupContext *ctx, const char *uri, const char *passwd);
|
||||
int (*login_account)(SipSetupContext *ctx, const char *uri, const char *passwd, const char *userid);
|
||||
int (*get_proxy)(SipSetupContext *ctx, const char *domain, char *proxy, size_t sz);
|
||||
int (*get_stun_servers)(SipSetupContext *ctx, char *stun1, char *stun2, size_t size);
|
||||
int (*get_relay)(SipSetupContext *ctx, char *relay, size_t size);
|
||||
|
|
@ -135,7 +135,7 @@ int sip_setup_context_account_exists(SipSetupContext *ctx, const char *uri);
|
|||
int sip_setup_context_account_validated(SipSetupContext *ctx, const char *uri);
|
||||
int sip_setup_context_create_account(SipSetupContext *ctx, const char *uri, const char *passwd, const char *email, int suscribe);
|
||||
int sip_setup_context_get_capabilities(SipSetupContext *ctx);
|
||||
int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd);
|
||||
int sip_setup_context_login_account(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid);
|
||||
int sip_setup_context_get_proxy(SipSetupContext *ctx, const char *domain, char *proxy, size_t sz);
|
||||
int sip_setup_context_get_stun_servers(SipSetupContext *ctx, char *stun1, char *stun2, size_t size);
|
||||
int sip_setup_context_get_relay(SipSetupContext *ctx, char *relay, size_t size);
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ static void guess_display_name(LinphoneAddress *from){
|
|||
ms_free(dn);
|
||||
}
|
||||
|
||||
static int sip_wizard_do_login(SipSetupContext * ctx, const char *uri, const char *passwd){
|
||||
static int sip_wizard_do_login(SipSetupContext * ctx, const char *uri, const char *passwd, const char *userid){
|
||||
LinphoneProxyConfig *cfg=sip_setup_context_get_proxy_config(ctx);
|
||||
LinphoneCore *lc=linphone_proxy_config_get_core(cfg);
|
||||
LinphoneAuthInfo *auth;
|
||||
|
|
|
|||
|
|
@ -698,19 +698,19 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
|
|||
* Audio part
|
||||
*/
|
||||
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp,
|
||||
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port:0, UPNP_CALL_RETRY_DELAY);
|
||||
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtp_port:0, UPNP_CALL_RETRY_DELAY);
|
||||
|
||||
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp,
|
||||
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port+1:0, UPNP_CALL_RETRY_DELAY);
|
||||
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtcp_port:0, UPNP_CALL_RETRY_DELAY);
|
||||
|
||||
/*
|
||||
* Video part
|
||||
*/
|
||||
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp,
|
||||
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port:0, UPNP_CALL_RETRY_DELAY);
|
||||
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtp_port:0, UPNP_CALL_RETRY_DELAY);
|
||||
|
||||
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp,
|
||||
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port+1:0, UPNP_CALL_RETRY_DELAY);
|
||||
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtcp_port:0, UPNP_CALL_RETRY_DELAY);
|
||||
}
|
||||
|
||||
ms_mutex_unlock(&lupnp->mutex);
|
||||
|
|
|
|||
98
coreapi/xml.c
Normal file
98
coreapi/xml.c
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
linphone
|
||||
Copyright (C) 2010-2013 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include "private.h"
|
||||
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/xmlwriter.h>
|
||||
#include <libxml/xpath.h>
|
||||
#include <libxml/xpathInternals.h>
|
||||
|
||||
|
||||
xmlparsing_context_t * linphone_xmlparsing_context_new(void) {
|
||||
xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)malloc(sizeof(xmlparsing_context_t));
|
||||
if (xmlCtx != NULL) {
|
||||
xmlCtx->doc = NULL;
|
||||
xmlCtx->xpath_ctx = NULL;
|
||||
xmlCtx->errorBuffer[0] = '\0';
|
||||
xmlCtx->warningBuffer[0] = '\0';
|
||||
}
|
||||
return xmlCtx;
|
||||
}
|
||||
|
||||
void linphone_xmlparsing_context_destroy(xmlparsing_context_t *ctx) {
|
||||
if (ctx->doc != NULL) {
|
||||
xmlFreeDoc(ctx->doc);
|
||||
ctx->doc = NULL;
|
||||
}
|
||||
if (ctx->xpath_ctx != NULL) {
|
||||
xmlXPathFreeContext(ctx->xpath_ctx);
|
||||
ctx->xpath_ctx = NULL;
|
||||
}
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
void linphone_xmlparsing_genericxml_error(void *ctx, const char *fmt, ...) {
|
||||
xmlparsing_context_t *xmlCtx = (xmlparsing_context_t *)ctx;
|
||||
int sl = strlen(xmlCtx->errorBuffer);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(xmlCtx->errorBuffer + sl, XMLPARSING_BUFFER_LEN - sl, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int linphone_create_xml_xpath_context(xmlparsing_context_t *xml_ctx) {
|
||||
if (xml_ctx->xpath_ctx != NULL) {
|
||||
xmlXPathFreeContext(xml_ctx->xpath_ctx);
|
||||
}
|
||||
xml_ctx->xpath_ctx = xmlXPathNewContext(xml_ctx->doc);
|
||||
if (xml_ctx->xpath_ctx == NULL) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char *xpath_expression) {
|
||||
xmlXPathObjectPtr xpath_obj;
|
||||
xmlChar *text = NULL;
|
||||
int i;
|
||||
|
||||
xpath_obj = xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx);
|
||||
if (xpath_obj != NULL) {
|
||||
if (xpath_obj->nodesetval != NULL) {
|
||||
xmlNodeSetPtr nodes = xpath_obj->nodesetval;
|
||||
for (i = 0; i < nodes->nodeNr; i++) {
|
||||
xmlNodePtr node = nodes->nodeTab[i];
|
||||
if (node->children != NULL) {
|
||||
text = xmlNodeListGetString(xml_ctx->doc, node->children, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
xmlXPathFreeObject(xpath_obj);
|
||||
}
|
||||
|
||||
return (char *)text;
|
||||
}
|
||||
|
||||
void linphone_free_xml_text_content(const char *text) {
|
||||
xmlFree((xmlChar *)text);
|
||||
}
|
||||
|
||||
xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression) {
|
||||
return xmlXPathEvalExpression((const xmlChar *)xpath_expression, xml_ctx->xpath_ctx);
|
||||
}
|
||||
|
|
@ -221,21 +221,27 @@ static int processDoc(xmlNode *node, xml2lpc_context *ctx) {
|
|||
}
|
||||
|
||||
static int internal_convert_xml2lpc(xml2lpc_context *ctx) {
|
||||
xmlNode *rootNode;
|
||||
int ret;
|
||||
|
||||
xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse started");
|
||||
xmlNode *rootNode = xmlDocGetRootElement(ctx->doc);
|
||||
rootNode = xmlDocGetRootElement(ctx->doc);
|
||||
//dumpNodes(0, rootNode, cbf, ctx);
|
||||
int ret = processDoc(rootNode, ctx);
|
||||
ret = processDoc(rootNode, ctx);
|
||||
xml2lpc_log(ctx, XML2LPC_DEBUG, "Parse ended ret:%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xml2lpc_validate(xml2lpc_context *xmlCtx) {
|
||||
xml2lpc_context_clear_logs(xmlCtx);
|
||||
xmlSchemaValidCtxtPtr validCtx;
|
||||
xmlSchemaParserCtxtPtr parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd);
|
||||
xmlSchemaParserCtxtPtr parserCtx;
|
||||
int ret;
|
||||
|
||||
xml2lpc_context_clear_logs(xmlCtx);
|
||||
parserCtx = xmlSchemaNewDocParserCtxt(xmlCtx->xsd);
|
||||
validCtx = xmlSchemaNewValidCtxt(xmlSchemaParse(parserCtx));
|
||||
xmlSchemaSetValidErrors(validCtx, xml2lpc_genericxml_error, xml2lpc_genericxml_warning, xmlCtx);
|
||||
int ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc);
|
||||
ret = xmlSchemaValidateDoc(validCtx, xmlCtx->doc);
|
||||
if(ret > 0) {
|
||||
if(strlen(xmlCtx->warningBuffer) > 0)
|
||||
xml2lpc_log(xmlCtx, XML2LPC_WARNING, "%s", xmlCtx->warningBuffer);
|
||||
|
|
@ -85,7 +85,7 @@ linphone_daemon_LDADD=$(top_builddir)/coreapi/liblinphone.la $(READLINE_LIBS) \
|
|||
$(MEDIASTREAMER_LIBS) \
|
||||
$(ORTP_LIBS) \
|
||||
$(SPEEX_LIBS) \
|
||||
$(OSIP_LIBS)
|
||||
$(LIBXML2_LIBS)
|
||||
|
||||
AM_CFLAGS=$(READLINE_CFLAGS) -DIN_LINPHONE $(STRICT_OPTIONS)
|
||||
AM_CXXFLAGS=$(READLINE_CXXFLAGS) -DIN_LINPHONE $(STRICT_OPTIONS)
|
||||
|
|
@ -96,5 +96,6 @@ INCLUDES = \
|
|||
-I$(top_srcdir)/include \
|
||||
$(ORTP_CFLAGS) \
|
||||
$(MEDIASTREAMER_CFLAGS) \
|
||||
$(BELLESIP_CFLAGS)
|
||||
$(BELLESIP_CFLAGS)\
|
||||
$(LIBXML2_CFLAGS)
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ void Video::exec(Daemon* app, const char* args)
|
|||
LinphoneCore *lc = app->getCore();
|
||||
int cid;
|
||||
LinphoneCall *call = NULL;
|
||||
bool current = false;
|
||||
bool activate = false;
|
||||
int argc = sscanf(args, "%i", &cid);
|
||||
|
||||
|
|
@ -40,7 +39,6 @@ void Video::exec(Daemon* app, const char* args)
|
|||
}
|
||||
} else {
|
||||
call = app->findCall(cid);
|
||||
current = true;
|
||||
if (call == NULL) {
|
||||
app->sendResponse(Response("No call with such id."));
|
||||
return;
|
||||
|
|
@ -94,7 +92,6 @@ void VideoSource::exec(Daemon* app, const char* args)
|
|||
LinphoneCall *call = NULL;
|
||||
int cid;
|
||||
int argc = 0;
|
||||
bool current = false;
|
||||
bool activate = false;
|
||||
char command[6];
|
||||
|
||||
|
|
@ -109,7 +106,6 @@ void VideoSource::exec(Daemon* app, const char* args)
|
|||
}
|
||||
} else if( argc == 2 ) {
|
||||
call = app->findCall(cid);
|
||||
current = true;
|
||||
if (call == NULL) {
|
||||
app->sendResponse(Response("No call with such id."));
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -515,7 +515,7 @@ void Daemon::iterateStreamStats() {
|
|||
while (it->second->queue && (NULL != (ev=ortp_ev_queue_get(it->second->queue)))){
|
||||
OrtpEventType evt=ortp_event_get_type(ev);
|
||||
if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED || evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
|
||||
linphone_call_stream_stats_hack(&it->second->stream->ms, &it->second->stats, ev);
|
||||
//linphone_call_stream_stats_hack(&it->second->stream->ms, &it->second->stats, ev);
|
||||
if (mUseStatsEvents) mEventQueue.push(new AudioStreamStatsResponse(this,
|
||||
it->second->stream, &it->second->stats, true));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,11 +175,11 @@ struct AudioStreamAndOther {
|
|||
LinphoneCallStats stats;
|
||||
AudioStreamAndOther(AudioStream *as) : stream(as) {
|
||||
queue = ortp_ev_queue_new();
|
||||
rtp_session_register_event_queue(as->ms.session, queue);
|
||||
rtp_session_register_event_queue(as->ms.sessions.rtp_session, queue);
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
}
|
||||
~AudioStreamAndOther() {
|
||||
rtp_session_unregister_event_queue(stream->ms.session, queue);
|
||||
rtp_session_unregister_event_queue(stream->ms.sessions.rtp_session, queue);
|
||||
ortp_ev_queue_destroy(queue);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,11 @@ UI_FILES= about.ui \
|
|||
tunnel_config.ui \
|
||||
waiting.ui \
|
||||
dscp_settings.ui \
|
||||
call_statistics.ui
|
||||
call_statistics.ui \
|
||||
ldap.ui \
|
||||
config-uri.ui \
|
||||
provisioning-fetch.ui \
|
||||
audio_assistant.ui
|
||||
|
||||
PIXMAPS= \
|
||||
stock_people.png
|
||||
|
|
@ -48,6 +52,8 @@ linphone_SOURCES= \
|
|||
loginframe.c \
|
||||
singleinstance.c \
|
||||
conference.c \
|
||||
config-fetching.c \
|
||||
audio_assistant.c \
|
||||
linphone.h
|
||||
if BUILD_WIZARD
|
||||
linphone_SOURCES+= \
|
||||
|
|
@ -55,7 +61,7 @@ linphone_SOURCES+= \
|
|||
endif
|
||||
|
||||
linphone_LDADD= $(top_builddir)/coreapi/liblinphone.la \
|
||||
$(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) $(SQLITE3_LIBS)
|
||||
$(LIBGTK_LIBS) $(NOTIFY1_LIBS) $(NOTIFY4_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) $(SQLITE3_LIBS) $(BELLESIP_LIBS)
|
||||
|
||||
|
||||
if BUILD_WIN32
|
||||
|
|
@ -77,7 +83,7 @@ endif
|
|||
|
||||
AM_CFLAGS= -DIN_LINPHONE -I$(top_srcdir)/coreapi/ \
|
||||
$(MEDIASTREAMER_CFLAGS) \
|
||||
$(ORTP_CFLAGS) \
|
||||
$(ORTP_CFLAGS) $(BELLESIP_CFLAGS) \
|
||||
$(STRICT_OPTIONS) $(LIBGTK_CFLAGS) $(LIBGTKMAC_CFLAGS) $(IPV6_CFLAGS) \
|
||||
$(TUNNEL_CFLAGS) \
|
||||
$(SQLITE3_CFLAGS)
|
||||
|
|
|
|||
469
gtk/audio_assistant.c
Normal file
469
gtk/audio_assistant.c
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
/*
|
||||
linphone, gtk-glade interface.
|
||||
Copyright (C) 2008 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "linphone.h"
|
||||
#include "linphonecore_utils.h"
|
||||
#include "mediastreamer2/mediastream.h"
|
||||
#include "mediastreamer2/msvolume.h"
|
||||
|
||||
static GtkWidget *audio_assistant=NULL;
|
||||
static void prepare(GtkAssistant *w);
|
||||
|
||||
GtkWidget *get_widget_from_assistant(const char *name){
|
||||
return (GtkWidget *)g_object_get_data(G_OBJECT(audio_assistant),name);
|
||||
}
|
||||
|
||||
static void set_widget_to_assistant(const char *name,GtkWidget *w){
|
||||
g_object_set_data(G_OBJECT(audio_assistant),name,w);
|
||||
}
|
||||
|
||||
static void update_record_button(gboolean is_visible){
|
||||
GtkWidget *rec_button = get_widget_from_assistant("rec_button");
|
||||
gtk_widget_set_sensitive(rec_button,is_visible);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void activate_record_button(gboolean is_active){
|
||||
GtkWidget *rec_button = get_widget_from_assistant("rec_button");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rec_button),is_active);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void update_play_button(gboolean is_visible){
|
||||
GtkWidget *play_button = get_widget_from_assistant("play_button");
|
||||
gtk_widget_set_sensitive(play_button,is_visible);
|
||||
}
|
||||
|
||||
static void activate_play_button(gboolean is_active){
|
||||
GtkWidget *play_button = get_widget_from_assistant("play_button");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),is_active);
|
||||
}
|
||||
|
||||
static gchar *get_record_file(){
|
||||
char filename[256]={0};
|
||||
char date[64]={0};
|
||||
time_t curtime=time(NULL);
|
||||
struct tm loctime;
|
||||
|
||||
#ifdef WIN32
|
||||
loctime=*localtime(&curtime);
|
||||
#else
|
||||
localtime_r(&curtime,&loctime);
|
||||
#endif
|
||||
snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i%2i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min, loctime.tm_sec);
|
||||
|
||||
snprintf(filename,sizeof(filename)-1,"record-%s.wav",date);
|
||||
return g_build_path(G_DIR_SEPARATOR_S,g_get_tmp_dir(),filename,NULL);;
|
||||
}
|
||||
|
||||
static float audio_stream_get_record_volume(AudioStream *st){
|
||||
if (st && st->volsend){
|
||||
float vol=0;
|
||||
ms_filter_call_method(st->volsend,MS_VOLUME_GET,&vol);
|
||||
return vol;
|
||||
}
|
||||
return LINPHONE_VOLUME_DB_LOWEST;
|
||||
}
|
||||
|
||||
static float audio_stream_get_max_volume(AudioStream *st){
|
||||
if (st && st->volsend){
|
||||
float vol=0;
|
||||
ms_filter_call_method(st->volsend,MS_VOLUME_GET_MAX,&vol);
|
||||
return vol;
|
||||
}
|
||||
return LINPHONE_VOLUME_DB_LOWEST;
|
||||
}
|
||||
|
||||
static gboolean update_audio_label(volume_ctx_t *ctx){
|
||||
float volume_db=ctx->get_volume(ctx->data);
|
||||
gchar *result;
|
||||
if (volume_db < -20) result = _("No voice detected");
|
||||
else if (volume_db <= -10) result = _("Too low");
|
||||
else if (volume_db < -6) result = _("Good");
|
||||
else result = _("Too loud");
|
||||
g_message("volume_max_db=%f, text=%s",volume_db,result);
|
||||
gtk_label_set_text(GTK_LABEL(ctx->widget),result);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void on_audio_label_destroy(guint task_id){
|
||||
g_source_remove(task_id);
|
||||
}
|
||||
|
||||
void linphone_gtk_init_audio_label(GtkWidget *w, get_volume_t get_volume, void *data){
|
||||
guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id_t"));
|
||||
if (task_id==0){
|
||||
volume_ctx_t *ctx=g_new(volume_ctx_t,1);
|
||||
ctx->widget=w;
|
||||
ctx->get_volume=get_volume;
|
||||
ctx->data=data;
|
||||
ctx->last_value=0;
|
||||
g_object_set_data_full(G_OBJECT(w),"ctx_t",ctx,g_free);
|
||||
task_id=g_timeout_add(200,(GSourceFunc)update_audio_label,ctx);
|
||||
g_object_set_data_full(G_OBJECT(w),"task_id_t",GINT_TO_POINTER(task_id),(GDestroyNotify)on_audio_label_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_gtk_uninit_audio_label(GtkWidget *w){
|
||||
guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id_t"));
|
||||
if (task_id!=0){
|
||||
g_object_set_data(G_OBJECT(w),"ctx_t",NULL);
|
||||
g_object_set_data(G_OBJECT(w),"task_id_t",NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void playback_device_changed(GtkWidget *w){
|
||||
gchar *sel=gtk_combo_box_get_active_text(GTK_COMBO_BOX(w));
|
||||
linphone_core_set_playback_device(linphone_gtk_get_core(),sel);
|
||||
g_free(sel);
|
||||
}
|
||||
|
||||
static void capture_device_changed(GtkWidget *capture_device){
|
||||
gchar *sel;
|
||||
GtkWidget *mic_audiolevel;
|
||||
GtkWidget *label_audiolevel;
|
||||
GtkWidget *assistant=gtk_widget_get_toplevel(capture_device);
|
||||
AudioStream *audio_stream;
|
||||
|
||||
mic_audiolevel = get_widget_from_assistant("mic_audiolevel");
|
||||
label_audiolevel = get_widget_from_assistant("label_audiolevel");
|
||||
audio_stream = (AudioStream *) g_object_get_data(G_OBJECT(assistant),"stream");
|
||||
sel = gtk_combo_box_get_active_text(GTK_COMBO_BOX(capture_device));
|
||||
linphone_core_set_capture_device(linphone_gtk_get_core(),sel);
|
||||
linphone_gtk_uninit_audio_meter(mic_audiolevel);
|
||||
linphone_gtk_uninit_audio_label(label_audiolevel);
|
||||
audio_stream_stop(audio_stream);
|
||||
g_free(sel);
|
||||
/*now restart the audio stream*/
|
||||
prepare(GTK_ASSISTANT(assistant));
|
||||
}
|
||||
|
||||
static void dialog_click(GtkWidget *dialog, guint response_id, GtkWidget *page){
|
||||
switch(response_id){
|
||||
case GTK_RESPONSE_YES:
|
||||
gtk_assistant_set_page_complete(GTK_ASSISTANT(audio_assistant),page,TRUE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay, void *data){
|
||||
ms_message("echo calibration finished %s.",status==LinphoneEcCalibratorDone ? "successfully" : "with faillure");
|
||||
if (status==LinphoneEcCalibratorDone) ms_message("Measured delay is %i",delay);
|
||||
|
||||
GtkWidget * dialog;
|
||||
GtkWidget *speaker_page = get_widget_from_assistant("speaker_page");
|
||||
|
||||
dialog = gtk_message_dialog_new (
|
||||
GTK_WINDOW(audio_assistant),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_QUESTION,
|
||||
GTK_BUTTONS_YES_NO,
|
||||
"%s","Did you hear three beeps ?");
|
||||
|
||||
g_signal_connect(G_OBJECT (dialog), "response",
|
||||
G_CALLBACK (dialog_click),speaker_page);
|
||||
gtk_widget_show(dialog);
|
||||
}
|
||||
|
||||
void linphone_gtk_start_sound(GtkWidget *w){
|
||||
LinphoneCore *lc = linphone_gtk_get_core();
|
||||
linphone_core_start_echo_calibration(lc,calibration_finished,NULL,NULL,NULL);
|
||||
}
|
||||
|
||||
static gboolean linphone_gtk_stop_record(gpointer data){
|
||||
AudioStream *stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"record_stream");
|
||||
if(stream != NULL){
|
||||
audio_stream_stop(stream);
|
||||
g_object_set_data(G_OBJECT(audio_assistant),"record_stream",NULL);
|
||||
}
|
||||
update_record_button(FALSE);
|
||||
update_play_button(TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void linphone_gtk_start_record_sound(GtkWidget *w, gpointer data){
|
||||
LinphoneCore *lc = linphone_gtk_get_core();
|
||||
AudioStream *stream = NULL;
|
||||
MSSndCardManager *manager = ms_snd_card_manager_get();
|
||||
gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
|
||||
|
||||
if(active){
|
||||
gchar *path = get_record_file();
|
||||
stream=audio_stream_new(8888, 8889, FALSE);
|
||||
if(stream != NULL){
|
||||
audio_stream_start_full(stream,&av_profile,"127.0.0.1",8888,"127.0.0.1",8889,0,0,NULL,
|
||||
path,NULL,ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE);
|
||||
g_object_set_data(G_OBJECT(audio_assistant),"record_stream",stream);
|
||||
}
|
||||
gint timeout_id = gtk_timeout_add(6000,(GtkFunction)linphone_gtk_stop_record,NULL);
|
||||
g_object_set_data(G_OBJECT(audio_assistant),"timeout_id",GINT_TO_POINTER(timeout_id));
|
||||
g_object_set_data(G_OBJECT(audio_assistant),"path",path);
|
||||
} else {
|
||||
stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"record_stream");
|
||||
gint timeout_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(audio_assistant),"timeout_id"));
|
||||
gtk_timeout_remove(timeout_id);
|
||||
if(stream != NULL){
|
||||
audio_stream_stop(stream);
|
||||
g_object_set_data(G_OBJECT(audio_assistant),"record_stream",NULL);
|
||||
}
|
||||
update_record_button(FALSE);
|
||||
update_play_button(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void endoffile_cb(void *ud, MSFilter *f, unsigned int ev,void * arg){
|
||||
switch (ev) {
|
||||
case MS_PLAYER_EOF: {
|
||||
ms_message("EndOfFile received");
|
||||
activate_play_button(FALSE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_gtk_start_play_record_sound(GtkWidget *w,gpointer data){
|
||||
LinphoneCore *lc = linphone_gtk_get_core();
|
||||
gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
|
||||
AudioStream *stream = NULL;
|
||||
MSSndCardManager *manager = ms_snd_card_manager_get();
|
||||
|
||||
if(active){
|
||||
gchar *path = g_object_get_data(G_OBJECT(audio_assistant),"path");
|
||||
stream=audio_stream_new(8888, 8889, FALSE);
|
||||
if(path != NULL){
|
||||
audio_stream_start_full(stream,&av_profile,"127.0.0.1",8888,"127.0.0.1",8889,0,0,path,
|
||||
NULL,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),NULL,FALSE);
|
||||
ms_filter_add_notify_callback(stream->soundread,endoffile_cb,stream,FALSE);
|
||||
g_object_set_data(G_OBJECT(audio_assistant),"play_stream",stream);
|
||||
}
|
||||
} else {
|
||||
stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"play_stream");
|
||||
if(stream != NULL){
|
||||
audio_stream_stop(stream);
|
||||
g_object_set_data(G_OBJECT(audio_assistant),"play_stream",NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GtkWidget *create_intro(){
|
||||
GtkWidget *vbox=gtk_vbox_new(FALSE,2);
|
||||
GtkWidget *label=gtk_label_new(_("Welcome !\nThis assistant will help you to configure audio settings for Linphone"));
|
||||
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2);
|
||||
gtk_widget_show_all(vbox);
|
||||
return vbox;
|
||||
}
|
||||
|
||||
static GtkWidget *create_mic_page(){
|
||||
GtkWidget *vbox=gtk_table_new(3,2,FALSE);
|
||||
LinphoneCore *lc=linphone_gtk_get_core();
|
||||
|
||||
GtkWidget *labelMicChoice=gtk_label_new(_("Capture device"));
|
||||
GtkWidget *labelMicLevel=gtk_label_new(_("Recorded volume"));
|
||||
GtkWidget *mic_audiolevel=gtk_progress_bar_new();
|
||||
GtkWidget *capture_device=gtk_combo_box_new();
|
||||
GtkWidget *box = gtk_vbox_new(FALSE,0);
|
||||
GtkWidget *label_audiolevel=gtk_label_new(_("No voice"));
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(box),mic_audiolevel,TRUE,TRUE,1);
|
||||
gtk_box_pack_start(GTK_BOX(box),label_audiolevel,FALSE,FALSE,1);
|
||||
|
||||
gtk_table_attach_defaults(GTK_TABLE(vbox), labelMicChoice, 0, 1, 0, 1);
|
||||
gtk_table_attach_defaults(GTK_TABLE(vbox), capture_device, 1, 2, 0, 1);
|
||||
gtk_table_attach_defaults(GTK_TABLE(vbox), labelMicLevel, 0, 1, 1, 2);
|
||||
gtk_table_attach_defaults(GTK_TABLE(vbox), box, 1, 2, 1, 2);
|
||||
|
||||
gtk_table_set_row_spacings(GTK_TABLE(vbox),10);
|
||||
|
||||
set_widget_to_assistant("mic_audiolevel",mic_audiolevel);
|
||||
set_widget_to_assistant("label_audiolevel",label_audiolevel);
|
||||
|
||||
const char **sound_devices=linphone_core_get_sound_devices(lc);
|
||||
linphone_gtk_fill_combo_box(capture_device, sound_devices,
|
||||
linphone_core_get_capture_device(lc), CAP_CAPTURE);
|
||||
gtk_widget_show_all(vbox);
|
||||
|
||||
g_signal_connect(G_OBJECT(capture_device),"changed",(GCallback)capture_device_changed,capture_device);
|
||||
|
||||
return vbox;
|
||||
}
|
||||
|
||||
static GtkWidget *create_speaker_page(){
|
||||
GtkWidget *vbox=gtk_table_new(2,2,FALSE);
|
||||
LinphoneCore *lc=linphone_gtk_get_core();
|
||||
|
||||
GtkWidget *labelSpeakerChoice=gtk_label_new(_("Playback device"));
|
||||
GtkWidget *labelSpeakerLevel=gtk_label_new(_("Play three beeps"));
|
||||
GtkWidget *spk_button=gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
|
||||
GtkWidget *playback_device=gtk_combo_box_new();
|
||||
|
||||
gtk_table_attach_defaults(GTK_TABLE(vbox), labelSpeakerChoice, 0, 1, 0, 1);
|
||||
gtk_table_attach_defaults(GTK_TABLE(vbox), playback_device, 1, 2, 0, 1);
|
||||
gtk_table_attach_defaults(GTK_TABLE(vbox), labelSpeakerLevel, 0, 1, 1, 2);
|
||||
gtk_table_attach(GTK_TABLE(vbox), spk_button, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0,0);
|
||||
|
||||
gtk_table_set_row_spacings(GTK_TABLE(vbox),10);
|
||||
|
||||
const char **sound_devices=linphone_core_get_sound_devices(lc);
|
||||
linphone_gtk_fill_combo_box(playback_device, sound_devices,
|
||||
linphone_core_get_playback_device(lc),CAP_PLAYBACK);
|
||||
gtk_widget_show_all(vbox);
|
||||
|
||||
set_widget_to_assistant("speaker_page",vbox);
|
||||
g_signal_connect(G_OBJECT(playback_device),"changed",(GCallback)playback_device_changed,playback_device);
|
||||
g_signal_connect(G_OBJECT(spk_button),"clicked",(GCallback)linphone_gtk_start_sound,vbox);
|
||||
|
||||
return vbox;
|
||||
}
|
||||
|
||||
static GtkWidget *create_play_record_page(){
|
||||
GtkWidget *vbox=gtk_table_new(2,2,FALSE);
|
||||
GtkWidget *labelRecord=gtk_label_new(_("Press the record button and say some words"));
|
||||
GtkWidget *labelPlay=gtk_label_new(_("Listen to your record voice"));
|
||||
GtkWidget *rec_button=gtk_toggle_button_new_with_label("Record");
|
||||
GtkWidget *play_button=gtk_toggle_button_new_with_label("Play");
|
||||
GtkWidget *image;
|
||||
|
||||
image=gtk_image_new_from_stock(GTK_STOCK_MEDIA_RECORD,GTK_ICON_SIZE_MENU);
|
||||
gtk_button_set_image(GTK_BUTTON(rec_button),image);
|
||||
|
||||
image=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY,GTK_ICON_SIZE_MENU);
|
||||
gtk_button_set_image(GTK_BUTTON(play_button),image);
|
||||
gtk_widget_set_sensitive(play_button,FALSE);
|
||||
|
||||
gtk_table_attach_defaults(GTK_TABLE(vbox), labelRecord, 0, 1, 0, 1);
|
||||
gtk_table_attach(GTK_TABLE(vbox), rec_button, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0,0);
|
||||
gtk_table_attach_defaults(GTK_TABLE(vbox), labelPlay, 0, 1, 1, 2);
|
||||
gtk_table_attach(GTK_TABLE(vbox), play_button, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0,0);
|
||||
|
||||
gtk_widget_show_all(vbox);
|
||||
|
||||
set_widget_to_assistant("rec_button",rec_button);
|
||||
set_widget_to_assistant("play_button",play_button);
|
||||
g_signal_connect(G_OBJECT(rec_button),"toggled",(GCallback)linphone_gtk_start_record_sound,vbox);
|
||||
g_signal_connect(G_OBJECT(play_button),"toggled",(GCallback)linphone_gtk_start_play_record_sound,vbox);
|
||||
|
||||
return vbox;
|
||||
}
|
||||
|
||||
static GtkWidget *create_end_page(){
|
||||
GtkWidget *vbox=gtk_vbox_new(FALSE,2);
|
||||
GtkWidget *label=gtk_label_new(_("Let's start Linphone now"));
|
||||
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 2);
|
||||
gtk_widget_show_all(vbox);
|
||||
return vbox;
|
||||
}
|
||||
|
||||
static void prepare(GtkAssistant *w){
|
||||
AudioStream *audio_stream = NULL;
|
||||
LinphoneCore *lc=linphone_gtk_get_core();
|
||||
int page = gtk_assistant_get_current_page(w);
|
||||
GtkWidget *mic_audiolevel = get_widget_from_assistant("mic_audiolevel");
|
||||
GtkWidget *label_audiolevel = get_widget_from_assistant("label_audiolevel");
|
||||
|
||||
//Speaker page
|
||||
if(page == 1){
|
||||
MSSndCardManager *manager = ms_snd_card_manager_get();
|
||||
audio_stream = audio_stream_start_with_sndcards(&av_profile,9898,"127.0.0.1",19898,0,0,ms_snd_card_manager_get_card(manager,linphone_core_get_playback_device(lc)),ms_snd_card_manager_get_card(manager,linphone_core_get_capture_device(lc)),FALSE);
|
||||
if (mic_audiolevel != NULL && audio_stream != NULL){
|
||||
g_object_set_data(G_OBJECT(audio_assistant),"stream",audio_stream);
|
||||
linphone_gtk_init_audio_meter(mic_audiolevel,(get_volume_t)audio_stream_get_record_volume,audio_stream);
|
||||
linphone_gtk_init_audio_label(label_audiolevel,(get_volume_t)audio_stream_get_max_volume,audio_stream);
|
||||
}
|
||||
} else if(page == 2 || page == 0){
|
||||
if(mic_audiolevel != NULL && label_audiolevel != NULL){
|
||||
audio_stream = (AudioStream *)g_object_get_data(G_OBJECT(audio_assistant),"stream");
|
||||
if(audio_stream != NULL){
|
||||
linphone_gtk_uninit_audio_meter(mic_audiolevel);
|
||||
linphone_gtk_uninit_audio_label(label_audiolevel);
|
||||
audio_stream_stop(audio_stream);
|
||||
g_object_set_data(G_OBJECT(audio_assistant),"stream",NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_gtk_close_audio_assistant(GtkWidget *w){
|
||||
gchar *path = g_object_get_data(G_OBJECT(audio_assistant),"path");
|
||||
if(path != NULL){
|
||||
g_unlink(path);
|
||||
}
|
||||
gtk_widget_destroy(w);
|
||||
if(linphone_gtk_get_audio_assistant_option()){
|
||||
gtk_main_quit();
|
||||
}
|
||||
audio_assistant = NULL;
|
||||
}
|
||||
|
||||
void linphone_gtk_audio_assistant_apply(GtkWidget *w){
|
||||
linphone_gtk_close_audio_assistant(w);
|
||||
}
|
||||
|
||||
void linphone_gtk_show_audio_assistant(void){
|
||||
GtkWidget *w;
|
||||
if(audio_assistant!=NULL)
|
||||
return;
|
||||
w=audio_assistant=linphone_gtk_create_window("audio_assistant");
|
||||
|
||||
gtk_window_set_resizable (GTK_WINDOW(w), FALSE);
|
||||
gtk_window_set_title(GTK_WINDOW(w),_("Audio Assistant"));
|
||||
|
||||
GtkWidget *welcome=create_intro();
|
||||
GtkWidget *mic_page=create_mic_page();
|
||||
GtkWidget *speaker_page=create_speaker_page();
|
||||
GtkWidget *play_record_page=create_play_record_page();
|
||||
GtkWidget *end_page=create_end_page();
|
||||
|
||||
gtk_assistant_append_page(GTK_ASSISTANT(w),welcome);
|
||||
gtk_assistant_set_page_type(GTK_ASSISTANT(w),welcome,GTK_ASSISTANT_PAGE_INTRO);
|
||||
gtk_assistant_set_page_title(GTK_ASSISTANT(w),welcome,_("Audio assistant"));
|
||||
gtk_assistant_set_page_complete(GTK_ASSISTANT(w),welcome,TRUE);
|
||||
|
||||
gtk_assistant_append_page(GTK_ASSISTANT(w),mic_page);
|
||||
gtk_assistant_set_page_type(GTK_ASSISTANT(w),mic_page,GTK_ASSISTANT_PAGE_CONTENT);
|
||||
gtk_assistant_set_page_title(GTK_ASSISTANT(w),mic_page,_("Mic Gain calibration"));
|
||||
gtk_assistant_set_page_complete(GTK_ASSISTANT(w),mic_page,TRUE);
|
||||
|
||||
gtk_assistant_append_page(GTK_ASSISTANT(w),speaker_page);
|
||||
gtk_assistant_set_page_type(GTK_ASSISTANT(w),speaker_page,GTK_ASSISTANT_PAGE_CONTENT);
|
||||
gtk_assistant_set_page_complete(GTK_ASSISTANT(w),speaker_page,FALSE);
|
||||
gtk_assistant_set_page_title(GTK_ASSISTANT(w),speaker_page,_("Speaker volume calibration"));
|
||||
|
||||
gtk_assistant_append_page(GTK_ASSISTANT(w),play_record_page);
|
||||
gtk_assistant_set_page_type(GTK_ASSISTANT(w),play_record_page,GTK_ASSISTANT_PAGE_CONTENT);
|
||||
gtk_assistant_set_page_complete(GTK_ASSISTANT(w),play_record_page,TRUE);
|
||||
gtk_assistant_set_page_title(GTK_ASSISTANT(w),play_record_page,_("Record and Play"));
|
||||
|
||||
gtk_assistant_append_page(GTK_ASSISTANT(w),end_page);
|
||||
gtk_assistant_set_page_type(GTK_ASSISTANT(w),end_page,GTK_ASSISTANT_PAGE_SUMMARY);
|
||||
gtk_assistant_set_page_complete(GTK_ASSISTANT(w),end_page,TRUE);
|
||||
gtk_assistant_set_page_title(GTK_ASSISTANT(w),end_page,_("Terminating"));
|
||||
|
||||
g_signal_connect(G_OBJECT(w),"close",(GCallback)linphone_gtk_close_audio_assistant,w);
|
||||
g_signal_connect(G_OBJECT(w),"cancel",(GCallback)linphone_gtk_close_audio_assistant,w);
|
||||
g_signal_connect(G_OBJECT(w),"prepare",(GCallback)prepare,NULL);
|
||||
|
||||
gtk_widget_show(w);
|
||||
}
|
||||
21
gtk/audio_assistant.ui
Normal file
21
gtk/audio_assistant.ui
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.16"/>
|
||||
<!-- interface-naming-policy project-wide -->
|
||||
<object class="GtkAssistant" id="audio_assistant">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">12</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.24"/>
|
||||
<requires lib="gtk+" version="2.16"/>
|
||||
<!-- interface-naming-policy project-wide -->
|
||||
<object class="GtkDialog" id="call_statistics">
|
||||
<property name="can_focus">False</property>
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
<object class="GtkTable" id="table1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="n_rows">7</property>
|
||||
<property name="n_rows">9</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
|
|
@ -224,6 +224,52 @@
|
|||
<property name="bottom_attach">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="video_size_recv_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Video resolution received</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">7</property>
|
||||
<property name="bottom_attach">8</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="video_size_recv">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">7</property>
|
||||
<property name="bottom_attach">8</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="video_size_sent_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Video resolution sent</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">8</property>
|
||||
<property name="bottom_attach">9</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="video_size_sent">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">8</property>
|
||||
<property name="bottom_attach">9</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -56,11 +56,13 @@ void linphone_gtk_call_log_chat_selected(GtkWidget *w){
|
|||
if (select!=NULL){
|
||||
GtkTreeModel *model=NULL;
|
||||
if (gtk_tree_selection_get_selected (select,&model,&iter)){
|
||||
gpointer pla;
|
||||
gpointer pcl;
|
||||
LinphoneAddress *la;
|
||||
gtk_tree_model_get(model,&iter,2,&pla,-1);
|
||||
la=(LinphoneAddress*)pla;
|
||||
if (la!=NULL){
|
||||
LinphoneCallLog *cl;
|
||||
gtk_tree_model_get(model,&iter,2,&pcl,-1);
|
||||
cl = (LinphoneCallLog *)pcl;
|
||||
la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl);
|
||||
if (la != NULL){
|
||||
linphone_gtk_friend_list_set_chat_conversation(la);
|
||||
}
|
||||
}
|
||||
|
|
@ -75,12 +77,14 @@ void linphone_gtk_call_log_add_contact(GtkWidget *w){
|
|||
if (select!=NULL){
|
||||
GtkTreeModel *model=NULL;
|
||||
if (gtk_tree_selection_get_selected (select,&model,&iter)){
|
||||
gpointer pla;
|
||||
gpointer pcl;
|
||||
LinphoneAddress *la;
|
||||
LinphoneCallLog *cl;
|
||||
LinphoneFriend *lf;
|
||||
gtk_tree_model_get(model,&iter,2,&pla,-1);
|
||||
la=(LinphoneAddress*)pla;
|
||||
if (la!=NULL){
|
||||
gtk_tree_model_get(model,&iter,2,&pcl,-1);
|
||||
cl = (LinphoneCallLog *)pcl;
|
||||
la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl);
|
||||
if (la != NULL){
|
||||
char *uri=linphone_address_as_string(la);
|
||||
lf=linphone_friend_new_with_address(uri);
|
||||
linphone_gtk_show_contact(lf);
|
||||
|
|
@ -92,16 +96,19 @@ void linphone_gtk_call_log_add_contact(GtkWidget *w){
|
|||
|
||||
static bool_t put_selection_to_uribar(GtkWidget *treeview){
|
||||
GtkTreeSelection *sel;
|
||||
|
||||
sel=gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
|
||||
if (sel!=NULL){
|
||||
GtkTreeModel *model=NULL;
|
||||
GtkTreeIter iter;
|
||||
if (gtk_tree_selection_get_selected (sel,&model,&iter)){
|
||||
char *tmp;
|
||||
gpointer pcl;
|
||||
LinphoneAddress *la;
|
||||
gtk_tree_model_get(model,&iter,2,&la,-1);
|
||||
tmp=linphone_address_as_string(la);
|
||||
LinphoneCallLog *cl;
|
||||
gtk_tree_model_get(model,&iter,2,&pcl,-1);
|
||||
cl = (LinphoneCallLog *)pcl;
|
||||
la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl);
|
||||
tmp = linphone_address_as_string(la);
|
||||
if(tmp!=NULL)
|
||||
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),tmp);
|
||||
ms_free(tmp);
|
||||
|
|
@ -131,10 +138,12 @@ static GtkWidget *linphone_gtk_create_call_log_menu(GtkWidget *call_log){
|
|||
if (select!=NULL){
|
||||
GtkTreeModel *model=NULL;
|
||||
if (gtk_tree_selection_get_selected (select,&model,&iter)){
|
||||
gpointer pla;
|
||||
gpointer pcl;
|
||||
LinphoneAddress *la;
|
||||
gtk_tree_model_get(model,&iter,2,&pla,-1);
|
||||
la=(LinphoneAddress*)pla;
|
||||
LinphoneCallLog *cl;
|
||||
gtk_tree_model_get(model,&iter,2,&pcl,-1);
|
||||
cl = (LinphoneCallLog *)pcl;
|
||||
la = linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl);
|
||||
name=linphone_address_as_string(la);
|
||||
call_label=g_strdup_printf(_("Call %s"),name);
|
||||
text_label=g_strdup_printf(_("Send text to %s"),name);
|
||||
|
|
@ -262,7 +271,7 @@ void linphone_gtk_call_log_update(GtkWidget *w){
|
|||
for (logs=linphone_core_get_call_logs(linphone_gtk_get_core());logs!=NULL;logs=logs->next){
|
||||
LinphoneCallLog *cl=(LinphoneCallLog*)logs->data;
|
||||
GtkTreeIter iter, iter2;
|
||||
const LinphoneAddress *la=linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl);
|
||||
LinphoneAddress *la=linphone_call_log_get_dir(cl)==LinphoneCallIncoming ? linphone_call_log_get_from(cl) : linphone_call_log_get_to(cl);
|
||||
char *addr= linphone_address_as_string(la);
|
||||
const char *display;
|
||||
gchar *logtxt, *headtxt, *minutes, *seconds;
|
||||
|
|
@ -284,8 +293,10 @@ void linphone_gtk_call_log_update(GtkWidget *w){
|
|||
#endif
|
||||
lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),addr);
|
||||
if(lf != NULL){
|
||||
la=linphone_friend_get_address(lf);
|
||||
display=linphone_address_get_display_name(la);
|
||||
if ((display=linphone_address_get_display_name(linphone_friend_get_address(lf)))) {
|
||||
/*update display name from friend*/
|
||||
linphone_address_set_display_name(la,display);
|
||||
}
|
||||
} else {
|
||||
display=linphone_address_get_display_name(la);
|
||||
}
|
||||
|
|
@ -295,6 +306,7 @@ void linphone_gtk_call_log_update(GtkWidget *w){
|
|||
display=linphone_address_get_domain (la);
|
||||
}
|
||||
}
|
||||
|
||||
if (linphone_call_log_get_quality(cl)!=-1){
|
||||
snprintf(quality,sizeof(quality),"%.1f",linphone_call_log_get_quality(cl));
|
||||
}else snprintf(quality,sizeof(quality)-1,"%s",_("n/a"));
|
||||
|
|
@ -338,9 +350,9 @@ void linphone_gtk_call_log_update(GtkWidget *w){
|
|||
GdkPixbuf *outgoing = create_pixbuf("call_status_outgoing.png");
|
||||
gtk_tree_store_set (store,&iter,
|
||||
0, linphone_call_log_get_dir(cl)==LinphoneCallOutgoing ? outgoing : incoming,
|
||||
1, headtxt,2,la,-1);
|
||||
1, headtxt,2,cl,-1);
|
||||
gtk_tree_store_append (store,&iter2,&iter);
|
||||
gtk_tree_store_set (store,&iter2,1,logtxt,2,la,-1);
|
||||
gtk_tree_store_set (store,&iter2,1,logtxt,-1);
|
||||
ms_free(addr);
|
||||
g_free(logtxt);
|
||||
g_free(headtxt);
|
||||
|
|
@ -398,4 +410,4 @@ GtkWidget * linphone_gtk_show_call_logs(void){
|
|||
linphone_gtk_call_log_update(w);
|
||||
}else gtk_window_present(GTK_WINDOW(w));
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
36
gtk/chat.c
36
gtk/chat.c
|
|
@ -279,6 +279,16 @@ static void on_chat_state_changed(LinphoneChatMessage *msg, LinphoneChatMessageS
|
|||
update_chat_state_message(state,msg);
|
||||
}
|
||||
|
||||
void linphone_gtk_compose_text(void) {
|
||||
GtkWidget *main_window=linphone_gtk_get_main_window();
|
||||
GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list");
|
||||
GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview");
|
||||
LinphoneChatRoom *cr=g_object_get_data(G_OBJECT(w),"cr");
|
||||
if (cr) {
|
||||
linphone_chat_room_compose(cr);
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_gtk_send_text(){
|
||||
GtkWidget *main_window=linphone_gtk_get_main_window();
|
||||
GtkWidget *friendlist=linphone_gtk_get_widget(main_window,"contact_list");
|
||||
|
|
@ -293,7 +303,11 @@ void linphone_gtk_send_text(){
|
|||
linphone_chat_room_send_message2(cr,msg,on_chat_state_changed,NULL);
|
||||
linphone_gtk_push_text(w,linphone_chat_message_get_from(msg),
|
||||
TRUE,cr,msg,FALSE);
|
||||
|
||||
// Disconnect and reconnect the "changed" signal to prevent triggering it when clearing the text entry.
|
||||
g_signal_handlers_disconnect_by_func(G_OBJECT(entry),(GCallback)linphone_gtk_compose_text,NULL);
|
||||
gtk_entry_set_text(GTK_ENTRY(entry),"");
|
||||
g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,7 +371,7 @@ void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){
|
|||
|
||||
GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with){
|
||||
GtkWidget *chat_view=linphone_gtk_create_widget("main","chatroom_frame");
|
||||
GtkWidget *main_window=linphone_gtk_get_main_window ();
|
||||
GtkWidget *main_window=linphone_gtk_get_main_window();
|
||||
GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
|
||||
GtkWidget *text=linphone_gtk_get_widget(chat_view,"textview");
|
||||
GdkColor color;
|
||||
|
|
@ -375,7 +389,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
|
|||
colorb.red = 56832;
|
||||
colorb.green = 60928;
|
||||
colorb.blue = 61952;
|
||||
|
||||
|
||||
with_str=linphone_address_as_string_uri_only(with);
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text),GTK_WRAP_WORD_CHAR);
|
||||
gtk_text_view_set_editable(GTK_TEXT_VIEW(text),FALSE);
|
||||
|
|
@ -410,6 +424,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
|
|||
g_signal_connect_swapped(G_OBJECT(button),"clicked",(GCallback)linphone_gtk_send_text,NULL);
|
||||
entry = linphone_gtk_get_widget(chat_view,"text_entry");
|
||||
g_signal_connect_swapped(G_OBJECT(entry),"activate",(GCallback)linphone_gtk_send_text,NULL);
|
||||
g_signal_connect_swapped(G_OBJECT(entry),"changed",(GCallback)linphone_gtk_compose_text,NULL);
|
||||
g_signal_connect(G_OBJECT(notebook),"switch_page",(GCallback)linphone_gtk_notebook_tab_select,NULL);
|
||||
ms_free(with_str);
|
||||
return chat_view;
|
||||
|
|
@ -417,7 +432,7 @@ GtkWidget* linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddres
|
|||
|
||||
LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with){
|
||||
char *tmp=linphone_address_as_string(with);
|
||||
LinphoneChatRoom *cr=linphone_core_create_chat_room(linphone_gtk_get_core(),tmp);
|
||||
LinphoneChatRoom *cr=linphone_core_get_or_create_chat_room(linphone_gtk_get_core(),tmp);
|
||||
ms_free(tmp);
|
||||
return cr;
|
||||
}
|
||||
|
|
@ -468,9 +483,10 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room,
|
|||
gboolean send=TRUE;
|
||||
/*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/
|
||||
const LinphoneAddress *from= linphone_chat_message_get_from ( msg );
|
||||
|
||||
|
||||
w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" );
|
||||
if ( w!=NULL ) {
|
||||
/* Chat window opened */
|
||||
const LinphoneAddress *from_chatview=linphone_gtk_friend_list_get_active_address();
|
||||
if (linphone_address_weak_equal(from,from_chatview)) {
|
||||
send=TRUE;
|
||||
|
|
@ -480,8 +496,13 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room,
|
|||
}
|
||||
send=FALSE;
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
/* Chat window closed */
|
||||
#ifdef MSG_STORAGE_ENABLED
|
||||
send=FALSE;
|
||||
#else
|
||||
send=TRUE;
|
||||
#endif
|
||||
if ( !linphone_gtk_friend_list_is_contact ( linphone_chat_message_get_from ( msg ) ) ) {
|
||||
linphone_gtk_chat_add_contact ( linphone_chat_message_get_from ( msg ) );
|
||||
}
|
||||
|
|
@ -507,6 +528,11 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room,
|
|||
linphone_gtk_push_text ( w,linphone_chat_message_get_from ( msg ),
|
||||
FALSE,room,msg,FALSE );
|
||||
}
|
||||
linphone_core_play_local(lc,linphone_gtk_get_sound_path("incoming_chat.wav"));
|
||||
linphone_gtk_show_friends();
|
||||
|
||||
}
|
||||
|
||||
void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) {
|
||||
linphone_gtk_friend_list_update_chat_picture();
|
||||
}
|
||||
|
|
|
|||
79
gtk/config-fetching.c
Normal file
79
gtk/config-fetching.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
linphone, gtk-glade interface.
|
||||
Copyright (C) 2008 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "linphone.h"
|
||||
#include "lpconfig.h"
|
||||
|
||||
|
||||
void linphone_gtk_set_configuration_uri(void){
|
||||
GtkWidget *w=linphone_gtk_create_window("config-uri");
|
||||
GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry");
|
||||
const char *uri=linphone_core_get_provisioning_uri(linphone_gtk_get_core());
|
||||
if (uri) gtk_entry_set_text(GTK_ENTRY(entry),uri);
|
||||
gtk_widget_show(w);
|
||||
}
|
||||
|
||||
void linphone_gtk_config_uri_changed(GtkWidget *button){
|
||||
GtkWidget *w=gtk_widget_get_toplevel(button);
|
||||
GtkWidget *entry=linphone_gtk_get_widget(w,"uri_entry");
|
||||
const char *uri=gtk_entry_get_text(GTK_ENTRY(entry));
|
||||
|
||||
if (uri && (strlen(uri)==0 || strcmp(uri,"https://")==0)) uri=NULL;
|
||||
|
||||
linphone_core_set_provisioning_uri(linphone_gtk_get_core(),uri);
|
||||
gtk_widget_destroy(w);
|
||||
|
||||
if (uri){
|
||||
linphone_gtk_schedule_restart();
|
||||
gtk_main_quit();
|
||||
}
|
||||
}
|
||||
|
||||
void linphone_gtk_config_uri_cancel(GtkWidget *button){
|
||||
GtkWidget *w=gtk_widget_get_toplevel(button);
|
||||
gtk_widget_destroy(w);
|
||||
}
|
||||
|
||||
GtkWidget * linphone_gtk_show_config_fetching(void){
|
||||
LinphoneCore *lc=linphone_gtk_get_core();
|
||||
GtkWidget *w=linphone_gtk_create_window("provisioning-fetch");
|
||||
g_message("Fetching started");
|
||||
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(w),_("fetching from %s"),linphone_core_get_provisioning_uri(lc));
|
||||
#if GTK_CHECK_VERSION(2,20,0)
|
||||
{
|
||||
GtkWidget *spinner=gtk_spinner_new();
|
||||
gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(w),spinner);
|
||||
}
|
||||
#endif
|
||||
gtk_widget_show(w);
|
||||
return w;
|
||||
}
|
||||
|
||||
void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state){
|
||||
LinphoneCore *lc=linphone_gtk_get_core();
|
||||
gtk_widget_destroy(w);
|
||||
g_message("Fetching finished");
|
||||
if (state==LinphoneConfiguringFailed){
|
||||
GtkWidget *msg=gtk_message_dialog_new(NULL,0,GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,_("Downloading of remote configuration from %s failed."),
|
||||
linphone_core_get_provisioning_uri(lc));
|
||||
g_signal_connect(G_OBJECT(msg),"response",(GCallback)gtk_widget_destroy,NULL);
|
||||
gtk_widget_show(msg);
|
||||
}
|
||||
}
|
||||
|
||||
99
gtk/config-uri.ui
Normal file
99
gtk/config-uri.ui
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.18"/>
|
||||
<!-- interface-naming-policy project-wide -->
|
||||
<object class="GtkDialog" id="config-uri">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="title" translatable="yes">Specifying a remote configuration URI</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="button2">
|
||||
<property name="label">gtk-undo</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="linphone_gtk_config_uri_cancel" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button1">
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="linphone_gtk_config_uri_changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">This dialog allows to set an http or https address when configuration is to be fetched at startup.
|
||||
Please enter or modify the configuration URI below. After clicking OK, Linphone will restart automatically in order to fetch and take into account the new configuration. </property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="width_chars">80</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="uri_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="text" translatable="yes">https://</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="0">button2</action-widget>
|
||||
<action-widget response="0">button1</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
@ -87,6 +87,18 @@ static GdkPixbuf *create_chat_picture(){
|
|||
return pixbuf;
|
||||
}
|
||||
|
||||
static GdkPixbuf *create_composing_unread_msg(){
|
||||
GdkPixbuf *pixbuf;
|
||||
pixbuf = create_pixbuf("composing_active_chat.png");
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static GdkPixbuf *create_composing_chat_picture(){
|
||||
GdkPixbuf *pixbuf;
|
||||
pixbuf = create_pixbuf("composing_chat.png");
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
void linphone_gtk_set_friend_status(GtkWidget *friendlist , LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img){
|
||||
GtkTreeIter iter;
|
||||
|
|
@ -227,15 +239,23 @@ void linphone_gtk_friend_list_update_chat_picture(){
|
|||
GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list");
|
||||
GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist));
|
||||
LinphoneChatRoom *cr=NULL;
|
||||
bool_t is_composing;
|
||||
int nbmsg=0;
|
||||
if (gtk_tree_model_get_iter_first(model,&iter)) {
|
||||
do{
|
||||
gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1);
|
||||
nbmsg=linphone_chat_room_get_unread_messages_count(cr);
|
||||
is_composing=linphone_chat_room_is_remote_composing(cr);
|
||||
if(nbmsg != 0){
|
||||
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1);
|
||||
if (is_composing == TRUE)
|
||||
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_unread_msg(),-1);
|
||||
else
|
||||
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_unread_msg(),-1);
|
||||
} else {
|
||||
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1);
|
||||
if (is_composing == TRUE)
|
||||
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_composing_chat_picture(),-1);
|
||||
else
|
||||
gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_CHAT,create_chat_picture(),-1);
|
||||
}
|
||||
}while(gtk_tree_model_iter_next(model,&iter));
|
||||
}
|
||||
|
|
@ -890,7 +910,11 @@ void linphone_gtk_contact_ok(GtkWidget *button){
|
|||
linphone_friend_set_inc_subscribe_policy(lf,allow_presence ? LinphoneSPAccept : LinphoneSPDeny);
|
||||
linphone_friend_send_subscribe(lf,show_presence);
|
||||
}
|
||||
name=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name")));
|
||||
|
||||
name = NULL;
|
||||
if(gtk_entry_get_text_length(GTK_ENTRY(linphone_gtk_get_widget(w,"name"))) != 0){
|
||||
name=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"name")));
|
||||
}
|
||||
uri=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"sip_address")));
|
||||
show_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"show_presence")));
|
||||
allow_presence=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"allow_presence")));
|
||||
|
|
@ -899,9 +923,10 @@ void linphone_gtk_contact_ok(GtkWidget *button){
|
|||
linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !"));
|
||||
return ;
|
||||
}
|
||||
linphone_address_set_display_name(friend_address,name);
|
||||
linphone_friend_set_address(lf,friend_address);
|
||||
|
||||
linphone_address_set_display_name(friend_address,name);
|
||||
linphone_friend_set_name(lf,name);
|
||||
linphone_friend_set_address(lf,friend_address);
|
||||
linphone_friend_send_subscribe(lf,show_presence);
|
||||
linphone_friend_set_inc_subscribe_policy(lf,allow_presence==TRUE ? LinphoneSPAccept : LinphoneSPDeny);
|
||||
if (linphone_friend_in_list(lf)) {
|
||||
|
|
@ -911,7 +936,6 @@ void linphone_gtk_contact_ok(GtkWidget *button){
|
|||
lf2=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri);
|
||||
ms_free(uri);
|
||||
if(lf2==NULL){
|
||||
linphone_friend_set_name(lf,name);
|
||||
linphone_core_add_friend(linphone_gtk_get_core(),lf);
|
||||
}
|
||||
}
|
||||
|
|
@ -1092,4 +1116,4 @@ gboolean linphone_gtk_contact_list_button_pressed(GtkWidget *widget, GdkEventBut
|
|||
void linphone_gtk_buddy_info_updated(LinphoneCore *lc, LinphoneFriend *lf){
|
||||
/*refresh the entire list*/
|
||||
linphone_gtk_show_friends();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -256,14 +256,25 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){
|
|||
const char *audio_media_connectivity = _("Direct or through server");
|
||||
const char *video_media_connectivity = _("Direct or through server");
|
||||
gboolean has_video=linphone_call_params_video_enabled(linphone_call_get_current_params(call));
|
||||
MSVideoSize size_received = linphone_call_params_get_received_video_size(linphone_call_get_current_params(call));
|
||||
MSVideoSize size_sent = linphone_call_params_get_sent_video_size(linphone_call_get_current_params(call));
|
||||
gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
|
||||
as->download_bandwidth,as->upload_bandwidth);
|
||||
|
||||
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp);
|
||||
g_free(tmp);
|
||||
if (has_video)
|
||||
if (has_video){
|
||||
gchar *size_r=g_strdup_printf(_("%ix%i"),size_received.width,size_received.height);
|
||||
gchar *size_s=g_strdup_printf(_("%ix%i"),size_sent.width,size_sent.height);
|
||||
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_recv")),size_r);
|
||||
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_sent")),size_s);
|
||||
|
||||
tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),vs->download_bandwidth,vs->upload_bandwidth);
|
||||
else tmp=NULL;
|
||||
g_free(size_r);
|
||||
g_free(size_s);
|
||||
} else {
|
||||
tmp=NULL;
|
||||
}
|
||||
gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp);
|
||||
if (tmp) g_free(tmp);
|
||||
if(as->upnp_state != LinphoneUpnpStateNotAvailable && as->upnp_state != LinphoneUpnpStateIdle) {
|
||||
|
|
@ -556,19 +567,12 @@ static gboolean linphone_gtk_in_call_view_refresh(LinphoneCall *call){
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct _volume_ctx{
|
||||
GtkWidget *widget;
|
||||
get_volume_t get_volume;
|
||||
void *data;
|
||||
float last_value;
|
||||
}volume_ctx_t;
|
||||
|
||||
#define UNSIGNIFICANT_VOLUME (-26)
|
||||
#define UNSIGNIFICANT_VOLUME (-23)
|
||||
#define SMOOTH 0.15
|
||||
|
||||
static gboolean update_audio_meter(volume_ctx_t *ctx){
|
||||
float volume_db=ctx->get_volume(ctx->data);
|
||||
float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME+3.0);
|
||||
float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME-3.0);
|
||||
if (frac<0) frac=0;
|
||||
if (frac>1.0) frac=1.0;
|
||||
if (frac<ctx->last_value){
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.24"/>
|
||||
<requires lib="gtk+" version="2.16"/>
|
||||
<!-- interface-naming-policy project-wide -->
|
||||
<object class="GtkWindow" id="keypad">
|
||||
<property name="can_focus">False</property>
|
||||
|
|
|
|||
669
gtk/ldap.ui
Normal file
669
gtk/ldap.ui
Normal file
|
|
@ -0,0 +1,669 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.16"/>
|
||||
<!-- interface-naming-policy project-wide -->
|
||||
<object class="GtkWindow" id="ldap">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">LDAP Settings</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="ldap_tab">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkFrame" id="ldap_connection_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment6">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkTable" id="table6">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="n_rows">5</property>
|
||||
<property name="n_columns">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label41">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xpad">1</property>
|
||||
<property name="label" translatable="yes">Server address:</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label43">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Authentication method:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label44">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Username:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label45">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Password:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="ldap_use_tls">
|
||||
<property name="label" translatable="yes">Use TLS Connection</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Not yet available</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_server">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_username">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_password">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="ldap_auth_method">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="model">liststore2</property>
|
||||
<property name="active">0</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="renderer1"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="label17">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes"><b>Connection</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="ldap_sasl_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkTable" id="table1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Bind DN</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Authname</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Realm</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_bind_dn">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_sasl_authname">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_sasl_realm">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes"><b>SASL</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="ldap_search_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment7">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkTable" id="table7">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="n_rows">5</property>
|
||||
<property name="n_columns">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label46">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Base object:</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label47">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Filter (%s for name):</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label48">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Name Attribute:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label49">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">SIP address attribute:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label50">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Attributes to query:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_base_object">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_filter">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_name_attribute">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_sip_attribute">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="ldap_attributes">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="label37">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes"><b>Search</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="ldap_misc_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment8">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkTable" id="table8">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label51">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Timeout for search:</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label52">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Max results:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="ldap_timeout">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
<property name="adjustment">timeout_adjustment</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="ldap_max_results">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="max_length">3</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="invisible_char_set">True</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
<property name="adjustment">result_adjustment</property>
|
||||
<property name="numeric">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="ldap_deref_aliases">
|
||||
<property name="label" translatable="yes">Follow Aliases</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="label40">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes"><b>Miscellaneous</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox20">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="ldap_save">
|
||||
<property name="label">gtk-apply</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="linphone_gtk_ldap_save" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="ldap_reset">
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="linphone_gtk_ldap_reset" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="liststore2">
|
||||
<columns>
|
||||
<!-- column-name authmethod -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">ANONYMOUS</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">SIMPLE</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">DIGEST-MD5</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">NTLM</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="result_adjustment">
|
||||
<property name="lower">1</property>
|
||||
<property name="upper">100</property>
|
||||
<property name="value">50</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="timeout_adjustment">
|
||||
<property name="lower">1</property>
|
||||
<property name="upper">100</property>
|
||||
<property name="value">10</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">10</property>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
@ -28,10 +28,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#endif
|
||||
#include "linphonecore.h"
|
||||
|
||||
#include "ldap/ldapprovider.h"
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# undef _
|
||||
# define _(String) gettext (String)
|
||||
# define _(String) dgettext (GETTEXT_PACKAGE,String)
|
||||
#else
|
||||
# define _(String) (String)
|
||||
# define ngettext(singular,plural,number) ((number>1) ? (plural) : (singular) )
|
||||
|
|
@ -46,6 +48,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define LINPHONE_VERSION LINPHONE_VERSION_DATE
|
||||
#endif
|
||||
|
||||
enum {
|
||||
COMPLETION_HISTORY,
|
||||
COMPLETION_LDAP
|
||||
};
|
||||
|
||||
typedef float (*get_volume_t)(void *data);
|
||||
|
||||
typedef struct _volume_ctx{
|
||||
GtkWidget *widget;
|
||||
get_volume_t get_volume;
|
||||
void *data;
|
||||
float last_value;
|
||||
}volume_ctx_t;
|
||||
|
||||
typedef enum {
|
||||
CAP_IGNORE,
|
||||
CAP_PLAYBACK,
|
||||
CAP_CAPTURE
|
||||
}DeviceCap;
|
||||
|
||||
enum {
|
||||
START_LINPHONE,
|
||||
START_AUDIO_ASSISTANT,
|
||||
START_LINPHONE_WITH_CALL
|
||||
};
|
||||
|
||||
GdkPixbuf * create_pixbuf(const gchar *filename);
|
||||
GdkPixbufAnimation *create_pixbuf_animation(const gchar *filename);
|
||||
void add_pixmap_directory(const gchar *directory);
|
||||
|
|
@ -85,6 +113,10 @@ int linphone_gtk_get_ui_config_int(const char *key, int def);
|
|||
void linphone_gtk_set_ui_config_int(const char *key , int val);
|
||||
void linphone_gtk_visibility_set(const char *hiddens, const char *window_name, GtkWidget *w, gboolean show);
|
||||
|
||||
LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void);
|
||||
void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap);
|
||||
int linphone_gtk_is_ldap_supported(void);
|
||||
|
||||
void linphone_gtk_open_browser(const char *url);
|
||||
void linphone_gtk_check_for_new_version(void);
|
||||
const char *linphone_gtk_get_lang(const char *config_file);
|
||||
|
|
@ -104,6 +136,7 @@ void linphone_gtk_send_text();
|
|||
GtkWidget * linphone_gtk_init_chatroom(LinphoneChatRoom *cr, const LinphoneAddress *with);
|
||||
LinphoneChatRoom * linphone_gtk_create_chatroom(const LinphoneAddress *with);
|
||||
void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg);
|
||||
void linphone_gtk_is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room);
|
||||
|
||||
void linphone_gtk_friend_list_update_chat_picture();
|
||||
void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la);
|
||||
|
|
@ -137,18 +170,29 @@ void linphone_gtk_unset_from_conference(LinphoneCall *call);
|
|||
void linphone_gtk_terminate_conference_participant(LinphoneCall *call);
|
||||
void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call);
|
||||
void linphone_gtk_update_video_button(LinphoneCall *call);
|
||||
typedef float (*get_volume_t)(void *data);
|
||||
void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data);
|
||||
void linphone_gtk_uninit_audio_meter(GtkWidget *w);
|
||||
|
||||
void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg);
|
||||
void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login);
|
||||
void linphone_gtk_exit_login_frame(void);
|
||||
void linphone_gtk_set_ui_config(const char *key, const char *value);
|
||||
|
||||
void linphone_gtk_log_uninit();
|
||||
|
||||
bool_t linphone_gtk_init_instance(const char *app_name, const char *addr_to_call);
|
||||
bool_t linphone_gtk_init_instance(const char *app_name, int option, const char *addr_to_call);
|
||||
void linphone_gtk_uninit_instance(void);
|
||||
void linphone_gtk_monitor_usb(void);
|
||||
void linphone_gtk_unmonitor_usb(void);
|
||||
|
||||
gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference);
|
||||
void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap);
|
||||
gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference);
|
||||
void linphone_gtk_schedule_restart(void);
|
||||
|
||||
void linphone_gtk_show_audio_assistant(void);
|
||||
gboolean linphone_gtk_get_audio_assistant_option(void);
|
||||
|
||||
void linphone_gtk_set_configuration_uri(void);
|
||||
GtkWidget * linphone_gtk_show_config_fetching(void);
|
||||
void linphone_gtk_close_config_fetching(GtkWidget *w, LinphoneConfiguringState state);
|
||||
const char *linphone_gtk_get_sound_path(const char *file);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,15 +20,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "linphone.h"
|
||||
|
||||
void linphone_gtk_login_frame_connect_clicked(GtkWidget *button);
|
||||
void test_button_clicked_cb(GtkWidget *button);
|
||||
void linphone_gtk_exit_login_frame(void);
|
||||
|
||||
enum {
|
||||
NetworkKindAdsl,
|
||||
NetworkKindOpticalFiber
|
||||
};
|
||||
|
||||
static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd){
|
||||
if (sip_setup_context_login_account(ssctx,identity,passwd)==0){
|
||||
static void do_login(SipSetupContext *ssctx, const char *identity, const char * passwd, const char *userid){
|
||||
if (sip_setup_context_login_account(ssctx,identity,passwd,userid)==0){
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,44 +37,38 @@ static gboolean do_login_noprompt(LinphoneProxyConfig *cfg){
|
|||
if (ssctx==NULL) return TRUE;/*not ready ?*/
|
||||
username=linphone_gtk_get_ui_config ("login_username",NULL);
|
||||
if (username==NULL) {
|
||||
linphone_gtk_set_ui_config_int("automatic_login",0);
|
||||
linphone_gtk_show_login_frame(cfg);
|
||||
linphone_gtk_show_login_frame(cfg,TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
addr=linphone_address_new(linphone_proxy_config_get_identity(cfg));
|
||||
linphone_address_set_username(addr,username);
|
||||
tmp=linphone_address_as_string (addr);
|
||||
do_login(ssctx,tmp,NULL);
|
||||
do_login(ssctx,tmp,NULL,NULL);
|
||||
linphone_address_destroy(addr);
|
||||
linphone_gtk_load_identities();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){
|
||||
void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg, gboolean disable_auto_login){
|
||||
GtkWidget *mw=linphone_gtk_get_main_window();
|
||||
GtkWidget *label=linphone_gtk_get_widget(mw,"login_label");
|
||||
const LinphoneAuthInfo *ai;
|
||||
gchar *str;
|
||||
LinphoneAddress *from;
|
||||
LinphoneCore *lc=linphone_gtk_get_core();
|
||||
int nettype;
|
||||
const char *passwd=NULL;
|
||||
|
||||
const char *userid=NULL;
|
||||
gboolean auto_login=linphone_gtk_get_ui_config_int("automatic_login",0);
|
||||
|
||||
if (linphone_core_get_download_bandwidth(lc)==512 &&
|
||||
linphone_core_get_upload_bandwidth(lc)==512)
|
||||
nettype=NetworkKindOpticalFiber;
|
||||
else nettype=NetworkKindAdsl;
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(mw,"login_internet_kind")),nettype);
|
||||
//gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(mw,"internet_kind")),nettype);
|
||||
|
||||
if (linphone_gtk_get_ui_config_int("automatic_login",0) ){
|
||||
if (auto_login && !disable_auto_login){
|
||||
g_timeout_add(250,(GSourceFunc)do_login_noprompt,cfg);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(mw,"automatic_login")),auto_login);
|
||||
|
||||
{
|
||||
const char *login_image=linphone_gtk_get_ui_config("login_image",NULL);
|
||||
const char *login_image=linphone_gtk_get_ui_config("login_image","linphone-banner.png");
|
||||
if (login_image){
|
||||
GdkPixbuf *pbuf=create_pixbuf (login_image);
|
||||
gtk_image_set_from_pixbuf (GTK_IMAGE(linphone_gtk_get_widget(mw,"login_image")),
|
||||
|
|
@ -89,6 +80,10 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){
|
|||
gtk_widget_hide(linphone_gtk_get_widget(mw,"disconnect_item"));
|
||||
gtk_widget_hide(linphone_gtk_get_widget(mw,"main_frame"));
|
||||
gtk_widget_show(linphone_gtk_get_widget(mw,"login_frame"));
|
||||
if (linphone_gtk_get_ui_config_int("login_needs_userid",FALSE)){
|
||||
gtk_widget_show(linphone_gtk_get_widget(mw,"userid"));
|
||||
gtk_widget_show(linphone_gtk_get_widget(mw,"login_userid"));
|
||||
}
|
||||
gtk_widget_set_sensitive(linphone_gtk_get_widget(mw,"options_menu"),FALSE);
|
||||
str=g_strdup_printf(_("Please enter login information for %s"),linphone_proxy_config_get_domain(cfg));
|
||||
gtk_label_set_text(GTK_LABEL(label),str);
|
||||
|
|
@ -107,9 +102,14 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){
|
|||
if (linphone_address_get_username(from)[0]!='?')
|
||||
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username")),
|
||||
linphone_address_get_username(from));
|
||||
if (ai) passwd=linphone_auth_info_get_passwd(ai);
|
||||
if (ai) {
|
||||
passwd=linphone_auth_info_get_passwd(ai);
|
||||
userid=linphone_auth_info_get_userid(ai);
|
||||
}
|
||||
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password")),
|
||||
passwd!=NULL ? passwd : "");
|
||||
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_userid")),
|
||||
userid ? userid : "");
|
||||
|
||||
linphone_address_destroy(from);
|
||||
}
|
||||
|
|
@ -130,8 +130,7 @@ void linphone_gtk_logout_clicked(){
|
|||
SipSetupContext *ss=linphone_proxy_config_get_sip_setup_context(cfg);
|
||||
if (ss){
|
||||
sip_setup_context_logout(ss);
|
||||
linphone_gtk_set_ui_config_int("automatic_login",FALSE);
|
||||
linphone_gtk_show_login_frame(cfg);
|
||||
linphone_gtk_show_login_frame(cfg,TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -142,6 +141,7 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){
|
|||
GtkWidget *mw=gtk_widget_get_toplevel(button);
|
||||
const char *username;
|
||||
const char *password;
|
||||
const char *userid;
|
||||
char *identity;
|
||||
gboolean autologin;
|
||||
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(mw),"login_proxy_config");
|
||||
|
|
@ -150,7 +150,8 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){
|
|||
|
||||
username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username")));
|
||||
password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_password")));
|
||||
|
||||
userid=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_userid")));
|
||||
|
||||
if (username==NULL || username[0]=='\0')
|
||||
return;
|
||||
|
||||
|
|
@ -161,19 +162,7 @@ void linphone_gtk_login_frame_connect_clicked(GtkWidget *button){
|
|||
from=linphone_address_new(linphone_proxy_config_get_identity(cfg));
|
||||
linphone_address_set_username(from,username);
|
||||
identity=linphone_address_as_string(from);
|
||||
do_login(ssctx,identity,password);
|
||||
do_login(ssctx,identity,password,userid);
|
||||
/*we need to refresh the identities since the proxy config may have changed.*/
|
||||
linphone_gtk_load_identities();
|
||||
}
|
||||
|
||||
void linphone_gtk_internet_kind_changed(GtkWidget *combo){
|
||||
int netkind_id=gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
|
||||
LinphoneCore *lc=linphone_gtk_get_core();
|
||||
if (netkind_id==NetworkKindAdsl){
|
||||
linphone_core_set_upload_bandwidth(lc,256);
|
||||
linphone_core_set_download_bandwidth(lc,512);
|
||||
}else if (netkind_id==NetworkKindOpticalFiber){
|
||||
linphone_core_set_upload_bandwidth(lc,512);
|
||||
linphone_core_set_download_bandwidth(lc,512);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
415
gtk/main.c
415
gtk/main.c
|
|
@ -45,18 +45,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include <libnotify/notify.h>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
#include <locale.h>
|
||||
#endif
|
||||
#define LINPHONE_ICON "linphone.png"
|
||||
|
||||
const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION;
|
||||
|
||||
static LinphoneCore *the_core=NULL;
|
||||
static GtkWidget *the_ui=NULL;
|
||||
static LinphoneLDAPContactProvider* ldap_provider = NULL;
|
||||
|
||||
static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str);
|
||||
static void linphone_gtk_registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState rs, const char *msg);
|
||||
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
|
||||
static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
|
||||
static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain);
|
||||
static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
|
||||
static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message);
|
||||
static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
|
||||
static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
|
||||
static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
|
||||
|
|
@ -69,22 +75,28 @@ void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpoi
|
|||
static gboolean linphone_gtk_auto_answer(LinphoneCall *call);
|
||||
void linphone_gtk_status_icon_set_blinking(gboolean val);
|
||||
void _linphone_gtk_enable_video(gboolean val);
|
||||
|
||||
void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data);
|
||||
static void linphone_gtk_init_ui(void);
|
||||
|
||||
#ifndef HAVE_GTK_OSX
|
||||
static gint main_window_x=0;
|
||||
static gint main_window_y=0;
|
||||
#endif
|
||||
static gboolean verbose=0;
|
||||
static gboolean quit_done=FALSE;
|
||||
static gboolean auto_answer = 0;
|
||||
static gchar * addr_to_call = NULL;
|
||||
static int start_option = START_LINPHONE;
|
||||
static gboolean no_video=FALSE;
|
||||
static gboolean iconified=FALSE;
|
||||
static gboolean run_audio_assistant=FALSE;
|
||||
static gchar *workingdir=NULL;
|
||||
static char *progpath=NULL;
|
||||
gchar *linphone_logfile=NULL;
|
||||
static gboolean workaround_gtk_entry_chinese_bug=FALSE;
|
||||
static gchar *custom_config_file=NULL;
|
||||
static gboolean restart=FALSE;
|
||||
static GtkWidget *config_fetching_dialog=NULL;
|
||||
|
||||
static GOptionEntry linphone_options[]={
|
||||
{
|
||||
|
|
@ -143,6 +155,13 @@ static GOptionEntry linphone_options[]={
|
|||
.arg_data = (gpointer) &custom_config_file,
|
||||
.description = N_("Configuration file")
|
||||
},
|
||||
{
|
||||
.long_name = "run-audio-assistant",
|
||||
.short_name = '\0',
|
||||
.arg = G_OPTION_ARG_NONE,
|
||||
.arg_data = (gpointer) &run_audio_assistant,
|
||||
.description = N_("Run the audio assistant")
|
||||
},
|
||||
{0}
|
||||
};
|
||||
|
||||
|
|
@ -231,11 +250,37 @@ static const char *linphone_gtk_get_factory_config_file(){
|
|||
return _factory_config_file;
|
||||
}
|
||||
|
||||
LinphoneLDAPContactProvider* linphone_gtk_get_ldap(void){
|
||||
return ldap_provider;
|
||||
}
|
||||
|
||||
int linphone_gtk_is_ldap_supported(void){
|
||||
return linphone_ldap_contact_provider_available();
|
||||
}
|
||||
|
||||
void linphone_gtk_set_ldap(LinphoneLDAPContactProvider* ldap)
|
||||
{
|
||||
if( ldap_provider )
|
||||
linphone_contact_provider_unref(ldap_provider);
|
||||
|
||||
ldap_provider = ldap ? linphone_ldap_contact_provider_ref( ldap )
|
||||
: NULL;
|
||||
}
|
||||
|
||||
void linphone_gtk_schedule_restart(void){
|
||||
restart=TRUE;
|
||||
}
|
||||
|
||||
gboolean linphone_gtk_get_audio_assistant_option(void){
|
||||
return run_audio_assistant;
|
||||
}
|
||||
|
||||
static void linphone_gtk_init_liblinphone(const char *config_file,
|
||||
const char *factory_config_file, const char *db_file) {
|
||||
LinphoneCoreVTable vtable={0};
|
||||
gchar *secrets_file=linphone_gtk_get_config_file(SECRETS_FILE);
|
||||
|
||||
vtable.global_state_changed=linphone_gtk_global_state_changed;
|
||||
vtable.call_state_changed=linphone_gtk_call_state_changed;
|
||||
vtable.registration_state_changed=linphone_gtk_registration_state_changed;
|
||||
vtable.notify_presence_received=linphone_gtk_notify_recv;
|
||||
|
|
@ -248,15 +293,25 @@ static void linphone_gtk_init_liblinphone(const char *config_file,
|
|||
vtable.call_log_updated=linphone_gtk_call_log_updated;
|
||||
//vtable.text_received=linphone_gtk_text_received;
|
||||
vtable.message_received=linphone_gtk_text_received;
|
||||
vtable.is_composing_received=linphone_gtk_is_composing_received;
|
||||
vtable.refer_received=linphone_gtk_refer_received;
|
||||
vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
|
||||
vtable.call_encryption_changed=linphone_gtk_call_encryption_changed;
|
||||
vtable.transfer_state_changed=linphone_gtk_transfer_state_changed;
|
||||
vtable.dtmf_received=linphone_gtk_dtmf_received;
|
||||
vtable.configuring_status=linphone_gtk_configuring_status;
|
||||
|
||||
the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
|
||||
linphone_core_migrate_to_multi_transport(the_core);
|
||||
//lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0);
|
||||
|
||||
|
||||
|
||||
if( lp_config_has_section(linphone_core_get_config(the_core),"ldap") ){
|
||||
LpConfig* cfg = linphone_core_get_config(the_core);
|
||||
LinphoneDictionary* ldap_cfg = lp_config_section_to_dict(cfg, "ldap");
|
||||
linphone_gtk_set_ldap( linphone_ldap_contact_provider_create(the_core, ldap_cfg) );
|
||||
}
|
||||
|
||||
linphone_core_set_user_agent(the_core,"Linphone", LINPHONE_VERSION);
|
||||
linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
|
||||
linphone_core_set_zrtp_secrets_file(the_core,secrets_file);
|
||||
|
|
@ -279,7 +334,7 @@ GtkWidget *linphone_gtk_get_main_window(){
|
|||
}
|
||||
|
||||
void linphone_gtk_destroy_main_window() {
|
||||
linphone_gtk_destroy_window(the_ui);
|
||||
linphone_gtk_destroy_window(the_ui);
|
||||
the_ui = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -335,6 +390,8 @@ GtkWidget *linphone_gtk_create_window(const char *window_name){
|
|||
|
||||
if (get_ui_file(window_name,path,sizeof(path))==-1) return NULL;
|
||||
|
||||
gtk_builder_set_translation_domain(builder,GETTEXT_PACKAGE);
|
||||
|
||||
if (!gtk_builder_add_from_file (builder, path, &error)){
|
||||
g_error("Couldn't load builder file: %s", error->message);
|
||||
g_error_free (error);
|
||||
|
|
@ -361,6 +418,9 @@ GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_n
|
|||
object_ids[1]=NULL;
|
||||
|
||||
if (get_ui_file(filename,path,sizeof(path))==-1) return NULL;
|
||||
|
||||
gtk_builder_set_translation_domain(builder,GETTEXT_PACKAGE);
|
||||
|
||||
if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){
|
||||
g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message);
|
||||
g_error_free (error);
|
||||
|
|
@ -559,23 +619,10 @@ static void update_video_title(){
|
|||
video_needs_update=TRUE;
|
||||
}
|
||||
|
||||
static gboolean linphone_gtk_iterate(LinphoneCore *lc){
|
||||
static gboolean first_time=TRUE;
|
||||
static void update_video_titles(LinphoneCore *lc){
|
||||
unsigned long id;
|
||||
static unsigned long previd=0;
|
||||
static unsigned long preview_previd=0;
|
||||
static gboolean in_iterate=FALSE;
|
||||
|
||||
/*avoid reentrancy*/
|
||||
if (in_iterate) return TRUE;
|
||||
in_iterate=TRUE;
|
||||
linphone_core_iterate(lc);
|
||||
if (first_time){
|
||||
/*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
|
||||
linphone_gtk_show_directory_search();
|
||||
first_time=FALSE;
|
||||
}
|
||||
|
||||
id=linphone_core_get_native_video_window_id(lc);
|
||||
if (id!=previd || video_needs_update){
|
||||
GdkWindow *w;
|
||||
|
|
@ -614,6 +661,23 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){
|
|||
if (video_needs_update) video_needs_update=FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean linphone_gtk_iterate(LinphoneCore *lc){
|
||||
static gboolean first_time=TRUE;
|
||||
static gboolean in_iterate=FALSE;
|
||||
|
||||
/*avoid reentrancy*/
|
||||
if (in_iterate) return TRUE;
|
||||
in_iterate=TRUE;
|
||||
linphone_core_iterate(lc);
|
||||
if (first_time){
|
||||
/*after the first call to iterate, SipSetupContexts should be ready, so take actions:*/
|
||||
linphone_gtk_show_directory_search();
|
||||
first_time=FALSE;
|
||||
}
|
||||
|
||||
update_video_titles(lc);
|
||||
if (addr_to_call!=NULL){
|
||||
/*make sure we are not showing the login screen*/
|
||||
GtkWidget *mw=linphone_gtk_get_main_window();
|
||||
|
|
@ -629,12 +693,31 @@ static gboolean linphone_gtk_iterate(LinphoneCore *lc){
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean uribar_completion_matchfunc(GtkEntryCompletion *completion, const gchar *key, GtkTreeIter *iter, gpointer user_data){
|
||||
char* address = NULL;
|
||||
gboolean ret = FALSE;
|
||||
gchar *tmp= NULL;
|
||||
gtk_tree_model_get(gtk_entry_completion_get_model(completion),iter,0,&address,-1);
|
||||
|
||||
tmp = g_utf8_casefold(address,-1);
|
||||
if (tmp){
|
||||
if (strstr(tmp,key))
|
||||
ret=TRUE;
|
||||
g_free(tmp);
|
||||
}
|
||||
|
||||
if( address)
|
||||
g_free(address);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void load_uri_history(){
|
||||
GtkEntry *uribar=GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar"));
|
||||
char key[20];
|
||||
int i;
|
||||
GtkEntryCompletion *gep=gtk_entry_completion_new();
|
||||
GtkListStore *model=gtk_list_store_new(1,G_TYPE_STRING);
|
||||
GtkListStore *model=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_INT);
|
||||
for (i=0;;i++){
|
||||
const char *uri;
|
||||
snprintf(key,sizeof(key),"uri%i",i);
|
||||
|
|
@ -642,14 +725,18 @@ static void load_uri_history(){
|
|||
if (uri!=NULL) {
|
||||
GtkTreeIter iter;
|
||||
gtk_list_store_append(model,&iter);
|
||||
gtk_list_store_set(model,&iter,0,uri,-1);
|
||||
gtk_list_store_set(model,&iter,0,uri,1,COMPLETION_HISTORY,-1);
|
||||
if (i==0) gtk_entry_set_text(uribar,uri);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
gtk_entry_completion_set_model(gep,GTK_TREE_MODEL(model));
|
||||
gtk_entry_completion_set_text_column(gep,0);
|
||||
gtk_entry_completion_set_popup_completion(gep, TRUE);
|
||||
gtk_entry_completion_set_match_func(gep,uribar_completion_matchfunc, NULL, NULL);
|
||||
gtk_entry_completion_set_minimum_key_length(gep,3);
|
||||
gtk_entry_set_completion(uribar,gep);
|
||||
g_signal_connect (G_OBJECT (uribar), "changed", G_CALLBACK(linphone_gtk_on_uribar_changed), NULL);
|
||||
}
|
||||
|
||||
static void save_uri_history(){
|
||||
|
|
@ -697,10 +784,129 @@ static void completion_add_text(GtkEntry *entry, const char *text){
|
|||
}
|
||||
/* and prepend it on top of the list */
|
||||
gtk_list_store_prepend(GTK_LIST_STORE(model),&iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,-1);
|
||||
gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,text,1,COMPLETION_HISTORY,-1);
|
||||
save_uri_history();
|
||||
}
|
||||
|
||||
void on_contact_provider_search_results( LinphoneContactSearch* req, MSList* friends, void* data )
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkEntry* uribar = GTK_ENTRY(data);
|
||||
GtkEntryCompletion* compl = gtk_entry_get_completion(uribar);
|
||||
GtkTreeModel* model = gtk_entry_completion_get_model(compl);
|
||||
GtkListStore* list = GTK_LIST_STORE(model);
|
||||
LinphoneLDAPContactSearch* search = linphone_ldap_contact_search_cast(req);
|
||||
gboolean valid;
|
||||
|
||||
// clear completion list from previous non-history entries
|
||||
valid = gtk_tree_model_get_iter_first(model,&iter);
|
||||
while(valid)
|
||||
{
|
||||
char* url;
|
||||
int type;
|
||||
gtk_tree_model_get(model,&iter, 0,&url, 1,&type, -1);
|
||||
|
||||
if (type != COMPLETION_HISTORY) {
|
||||
valid = gtk_list_store_remove(list, &iter);
|
||||
} else {
|
||||
valid = gtk_tree_model_iter_next(model,&iter);
|
||||
}
|
||||
|
||||
if( url ) g_free(url);
|
||||
if( !valid ) break;
|
||||
}
|
||||
|
||||
// add new non-history related matches
|
||||
while( friends ){
|
||||
LinphoneFriend* lf = friends->data;
|
||||
if( lf ) {
|
||||
const LinphoneAddress* la = linphone_friend_get_address(lf);
|
||||
if( la ){
|
||||
char *addr = linphone_address_as_string(la);
|
||||
|
||||
if( addr ){
|
||||
ms_message("[LDAP]Insert match: %s", addr);
|
||||
gtk_list_store_insert_with_values(list, &iter, -1,
|
||||
0, addr,
|
||||
1, COMPLETION_LDAP, -1);
|
||||
ms_free(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
friends = friends->next;
|
||||
}
|
||||
gtk_entry_completion_complete(compl);
|
||||
// save the number of LDAP results to better decide if new results should be fetched when search predicate gets bigger
|
||||
gtk_object_set_data(GTK_OBJECT(uribar), "ldap_res_cout",
|
||||
GINT_TO_POINTER(
|
||||
linphone_ldap_contact_search_result_count(search)
|
||||
)
|
||||
);
|
||||
|
||||
// Gtk bug? we need to emit a "changed" signal so that the completion appears if
|
||||
// the list of results was previously empty
|
||||
g_signal_handlers_block_by_func(uribar, linphone_gtk_on_uribar_changed, NULL);
|
||||
g_signal_emit_by_name(uribar, "changed");
|
||||
g_signal_handlers_unblock_by_func(uribar, linphone_gtk_on_uribar_changed, NULL);
|
||||
}
|
||||
|
||||
struct CompletionTimeout {
|
||||
guint timeout_id;
|
||||
};
|
||||
|
||||
static gboolean launch_contact_provider_search(void *userdata)
|
||||
{
|
||||
LinphoneLDAPContactProvider* ldap = linphone_gtk_get_ldap();
|
||||
GtkWidget* uribar = GTK_WIDGET(userdata);
|
||||
const gchar* predicate = gtk_entry_get_text(GTK_ENTRY(uribar));
|
||||
gchar* previous_search = gtk_object_get_data(GTK_OBJECT(uribar), "previous_search");
|
||||
unsigned int prev_res_count = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "ldap_res_cout"));
|
||||
|
||||
if( ldap && strlen(predicate) >= 3 ){ // don't search too small predicates
|
||||
unsigned int max_res_count = linphone_ldap_contact_provider_get_max_result(ldap);
|
||||
|
||||
if( previous_search &&
|
||||
(strstr(predicate, previous_search) == predicate) && // last search contained results from this one
|
||||
(prev_res_count != max_res_count) ){ // and we didn't reach the max result limit
|
||||
|
||||
ms_message("Don't launch search on already searched data (current: %s, old search: %s), (%d/%d results)",
|
||||
predicate, previous_search, prev_res_count, max_res_count);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// save current search
|
||||
if( previous_search ) ms_free(previous_search);
|
||||
gtk_object_set_data(GTK_OBJECT(uribar), "previous_search", ms_strdup(predicate));
|
||||
|
||||
ms_message("launch_contact_provider_search");
|
||||
LinphoneContactSearch* search =linphone_contact_provider_begin_search(
|
||||
linphone_contact_provider_cast(ldap_provider),
|
||||
predicate, on_contact_provider_search_results, uribar
|
||||
);
|
||||
|
||||
if(search)
|
||||
linphone_contact_search_ref(search);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void linphone_gtk_on_uribar_changed(GtkEditable *uribar, gpointer user_data)
|
||||
{
|
||||
if( linphone_gtk_get_ldap() ) {
|
||||
gchar* text = gtk_editable_get_chars(uribar, 0,-1);
|
||||
gint timeout = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(uribar), "complete_timeout"));
|
||||
if( text ) g_free(text);
|
||||
|
||||
if( timeout != 0 ) {
|
||||
g_source_remove(timeout);
|
||||
}
|
||||
|
||||
timeout = g_timeout_add_seconds(1,(GSourceFunc)launch_contact_provider_search, uribar);
|
||||
|
||||
gtk_object_set_data(GTK_OBJECT(uribar),"complete_timeout", GINT_TO_POINTER(timeout) );
|
||||
}
|
||||
}
|
||||
|
||||
bool_t linphone_gtk_video_enabled(void){
|
||||
const LinphoneVideoPolicy *vpol=linphone_core_get_video_policy(linphone_gtk_get_core());
|
||||
return vpol->automatically_accept && vpol->automatically_initiate;
|
||||
|
|
@ -1064,6 +1270,11 @@ static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){
|
|||
status);
|
||||
}
|
||||
|
||||
static void linphone_gtk_configuring_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) {
|
||||
if (config_fetching_dialog) linphone_gtk_close_config_fetching(config_fetching_dialog, status);
|
||||
config_fetching_dialog=NULL;
|
||||
}
|
||||
|
||||
static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg){
|
||||
linphone_gtk_display_something(GTK_MESSAGE_INFO,msg);
|
||||
}
|
||||
|
|
@ -1173,6 +1384,24 @@ void linphone_gtk_notify(LinphoneCall *call, const char *msg){
|
|||
}
|
||||
}
|
||||
|
||||
static void linphone_gtk_global_state_changed(LinphoneCore *lc, LinphoneGlobalState state, const char*str){
|
||||
switch(state){
|
||||
case LinphoneGlobalStartup:
|
||||
the_core=lc;
|
||||
break;
|
||||
case LinphoneGlobalConfiguring:
|
||||
if (linphone_core_get_provisioning_uri(lc)){
|
||||
config_fetching_dialog=linphone_gtk_show_config_fetching();
|
||||
}
|
||||
break;
|
||||
case LinphoneGlobalOn:
|
||||
linphone_gtk_init_ui();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void on_call_updated_response(GtkWidget *dialog, gint responseid, LinphoneCall *call){
|
||||
if (linphone_call_get_state(call)==LinphoneCallUpdatedByRemote){
|
||||
LinphoneCore *lc=linphone_call_get_core(call);
|
||||
|
|
@ -1424,7 +1653,7 @@ static void linphone_gtk_init_status_icon(){
|
|||
const char *title;
|
||||
title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone"));
|
||||
icon=gtk_status_icon_new_from_pixbuf(pbuf);
|
||||
#if GTK_CHECK_VERSION(2,20,0)
|
||||
#if GTK_CHECK_VERSION(2,20,2)
|
||||
gtk_status_icon_set_name(icon,title);
|
||||
#endif
|
||||
g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)handle_icon_click,NULL);
|
||||
|
|
@ -1666,7 +1895,7 @@ void linphone_gtk_manage_login(void){
|
|||
if (cfg){
|
||||
SipSetup *ss=linphone_proxy_config_get_sip_setup(cfg);
|
||||
if (ss && (sip_setup_get_capabilities(ss) & SIP_SETUP_CAP_LOGIN)){
|
||||
linphone_gtk_show_login_frame(cfg);
|
||||
linphone_gtk_show_login_frame(cfg,FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1865,22 +2094,32 @@ static void linphone_gtk_check_soundcards(){
|
|||
}
|
||||
}
|
||||
|
||||
static void linphone_gtk_quit_core(void){
|
||||
linphone_gtk_unmonitor_usb();
|
||||
g_source_remove_by_user_data(linphone_gtk_get_core());
|
||||
#ifdef BUILD_WIZARD
|
||||
linphone_gtk_close_assistant();
|
||||
#endif
|
||||
linphone_gtk_set_ldap(NULL);
|
||||
linphone_gtk_destroy_log_window();
|
||||
linphone_core_destroy(the_core);
|
||||
linphone_gtk_log_uninit();
|
||||
}
|
||||
|
||||
static void linphone_gtk_quit(void){
|
||||
static gboolean quit_done=FALSE;
|
||||
if (!quit_done){
|
||||
quit_done=TRUE;
|
||||
linphone_gtk_unmonitor_usb();
|
||||
g_source_remove_by_user_data(linphone_gtk_get_core());
|
||||
#ifdef BUILD_WIZARD
|
||||
linphone_gtk_close_assistant();
|
||||
#endif
|
||||
linphone_gtk_quit_core();
|
||||
linphone_gtk_uninit_instance();
|
||||
linphone_gtk_destroy_log_window();
|
||||
linphone_core_destroy(the_core);
|
||||
linphone_gtk_log_uninit();
|
||||
#ifndef HAVE_GTK_OSX
|
||||
g_object_unref(icon);
|
||||
icon=NULL;
|
||||
#endif
|
||||
#ifdef HAVE_NOTIFY
|
||||
notify_uninit();
|
||||
#endif
|
||||
gtk_widget_destroy(the_ui);
|
||||
the_ui=NULL;
|
||||
gdk_threads_leave();
|
||||
}
|
||||
}
|
||||
|
|
@ -1900,14 +2139,39 @@ static gboolean on_block_termination(void){
|
|||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
#ifdef ENABLE_NLS
|
||||
void *p;
|
||||
static void linphone_gtk_init_ui(void){
|
||||
linphone_gtk_init_main_window();
|
||||
|
||||
#ifdef BUILD_WIZARD
|
||||
// Veryfing if at least one sip account is configured. If not, show wizard
|
||||
if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
|
||||
linphone_gtk_show_assistant();
|
||||
}
|
||||
#endif
|
||||
|
||||
if(run_audio_assistant){
|
||||
linphone_gtk_show_audio_assistant();
|
||||
start_option=START_AUDIO_ASSISTANT;
|
||||
iconified = TRUE;
|
||||
}
|
||||
#ifndef HAVE_GTK_OSX
|
||||
linphone_gtk_init_status_icon();
|
||||
#endif
|
||||
if (!iconified){
|
||||
linphone_gtk_show_main_window();
|
||||
linphone_gtk_check_soundcards();
|
||||
}
|
||||
if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
|
||||
linphone_gtk_check_for_new_version();
|
||||
linphone_gtk_monitor_usb();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
char *config_file;
|
||||
const char *factory_config_file;
|
||||
const char *lang;
|
||||
GtkSettings *settings;
|
||||
const char *icon_path=LINPHONE_ICON;
|
||||
GdkPixbuf *pbuf;
|
||||
const char *app_name="Linphone";
|
||||
LpConfig *factory;
|
||||
|
|
@ -1922,7 +2186,6 @@ int main(int argc, char *argv[]){
|
|||
|
||||
config_file=linphone_gtk_get_config_file(NULL);
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
/*workaround for windows: sometimes LANG is defined to an integer value, not understood by gtk */
|
||||
if ((lang=getenv("LANG"))!=NULL){
|
||||
|
|
@ -1953,10 +2216,11 @@ int main(int argc, char *argv[]){
|
|||
}
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
p=bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
|
||||
if (p==NULL) perror("bindtextdomain failed");
|
||||
bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
setlocale(LC_ALL,"");
|
||||
/*do not use textdomain(): this sets a global default domain. On Mac OS bundle, it breaks gtk translations (obscure bug somewhere)*/
|
||||
/*textdomain (GETTEXT_PACKAGE);*/
|
||||
#else
|
||||
g_message("NLS disabled.\n");
|
||||
#endif
|
||||
|
|
@ -1979,6 +2243,9 @@ int main(int argc, char *argv[]){
|
|||
}
|
||||
config_file=linphone_gtk_get_config_file(custom_config_file);
|
||||
|
||||
if(run_audio_assistant) start_option=START_AUDIO_ASSISTANT;
|
||||
if(addr_to_call != NULL) start_option=START_LINPHONE_WITH_CALL;
|
||||
|
||||
settings=gtk_settings_get_default();
|
||||
g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
|
||||
g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON));
|
||||
|
|
@ -1990,7 +2257,18 @@ int main(int argc, char *argv[]){
|
|||
g_error("Could not change directory to %s : %s",workingdir,strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(__APPLE__) && defined(ENABLE_NLS)
|
||||
/*workaround for bundles. GTK is unable to find translations in the bundle (obscure bug again).
|
||||
So we help it:*/
|
||||
{
|
||||
if (g_file_test(PACKAGE_LOCALE_DIR, G_FILE_TEST_IS_DIR)){
|
||||
bindtextdomain("gtk20",PACKAGE_LOCALE_DIR);
|
||||
bindtextdomain("gdk-pixbuf",PACKAGE_LOCALE_DIR);
|
||||
bindtextdomain("glib20",PACKAGE_LOCALE_DIR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Now, look for the factory configuration file, we do it this late
|
||||
since we want to have had time to change directory and to parse
|
||||
the options, in case we needed to access the working directory */
|
||||
|
|
@ -1999,14 +2277,11 @@ int main(int argc, char *argv[]){
|
|||
factory=lp_config_new(NULL);
|
||||
lp_config_read_file(factory,factory_config_file);
|
||||
app_name=lp_config_get_string(factory,"GtkUi","title","Linphone");
|
||||
icon_path=lp_config_get_string(factory,"GtkUi","icon",LINPHONE_ICON);
|
||||
}
|
||||
|
||||
if (linphone_gtk_init_instance(app_name, addr_to_call) == FALSE){
|
||||
g_warning("Another running instance of linphone has been detected. It has been woken-up.");
|
||||
g_warning("This instance is going to exit now.");
|
||||
gdk_threads_leave();
|
||||
return 0;
|
||||
}
|
||||
g_set_application_name(app_name);
|
||||
pbuf=create_pixbuf(icon_path);
|
||||
if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
|
||||
|
||||
add_pixmap_directory("pixmaps");
|
||||
add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone");
|
||||
|
|
@ -2019,48 +2294,40 @@ int main(int argc, char *argv[]){
|
|||
g_signal_connect(G_OBJECT(theMacApp),"NSApplicationBlockTermination",(GCallback)on_block_termination,NULL);
|
||||
#endif
|
||||
|
||||
core_start:
|
||||
if (linphone_gtk_init_instance(app_name, start_option, addr_to_call) == FALSE){
|
||||
g_warning("Another running instance of linphone has been detected. It has been woken-up.");
|
||||
g_warning("This instance is going to exit now.");
|
||||
gdk_threads_leave();
|
||||
return 0;
|
||||
}
|
||||
|
||||
the_ui=linphone_gtk_create_window("main");
|
||||
|
||||
g_object_set_data(G_OBJECT(the_ui),"is_created",GINT_TO_POINTER(FALSE));
|
||||
|
||||
linphone_gtk_create_log_window();
|
||||
linphone_core_enable_logs_with_cb(linphone_gtk_log_handler);
|
||||
|
||||
|
||||
db_file=linphone_gtk_message_storage_get_db_file(NULL);
|
||||
|
||||
linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file);
|
||||
|
||||
g_set_application_name(app_name);
|
||||
pbuf=create_pixbuf(linphone_gtk_get_ui_config("icon",LINPHONE_ICON));
|
||||
if (pbuf!=NULL) gtk_window_set_default_icon(pbuf);
|
||||
|
||||
|
||||
/* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/
|
||||
gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core());
|
||||
gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)NULL);
|
||||
linphone_gtk_init_main_window();
|
||||
|
||||
#ifdef BUILD_WIZARD
|
||||
// Veryfing if at least one sip account is configured. If not, show wizard
|
||||
if (linphone_core_get_proxy_config_list(linphone_gtk_get_core()) == NULL) {
|
||||
linphone_gtk_show_assistant();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GTK_OSX
|
||||
linphone_gtk_init_status_icon();
|
||||
#endif
|
||||
if (!iconified){
|
||||
linphone_gtk_show_main_window();
|
||||
linphone_gtk_check_soundcards();
|
||||
}
|
||||
if (linphone_gtk_get_ui_config_int("update_check_menu",0)==0)
|
||||
linphone_gtk_check_for_new_version();
|
||||
linphone_gtk_monitor_usb();
|
||||
|
||||
gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)linphone_gtk_get_core());
|
||||
|
||||
gtk_main();
|
||||
linphone_gtk_quit();
|
||||
|
||||
if (restart){
|
||||
quit_done=FALSE;
|
||||
restart=FALSE;
|
||||
goto core_start;
|
||||
}
|
||||
#ifndef HAVE_GTK_OSX
|
||||
/*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/
|
||||
gtk_status_icon_set_visible(icon,FALSE);
|
||||
if (icon) gtk_status_icon_set_visible(icon,FALSE);
|
||||
#endif
|
||||
free(progpath);
|
||||
return 0;
|
||||
|
|
|
|||
186
gtk/main.ui
186
gtk/main.ui
|
|
@ -786,6 +786,12 @@
|
|||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="image21">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="yalign">0.49000000953674316</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="image3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
|
|
@ -821,6 +827,59 @@
|
|||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
</object>
|
||||
<object class="GtkListStore" id="model1">
|
||||
<columns>
|
||||
<!-- column-name gchararray -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">All users</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Online users</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkListStore" id="model2">
|
||||
<columns>
|
||||
<!-- column-name gchararray -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">ADSL</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Fiber Channel</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkListStore" id="model3">
|
||||
<columns>
|
||||
<!-- column-name gchararray -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Default</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkListStore" id="model4">
|
||||
<columns>
|
||||
<!-- column-name gchararray -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">ADSL</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Fiber Channel</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkWindow" id="main">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||
|
|
@ -858,6 +917,16 @@
|
|||
<signal name="activate" handler="linphone_gtk_show_parameters" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="provisionning_item">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="label" translatable="yes">Set configuration URI</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="linphone_gtk_set_configuration_uri" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="disconnect_item">
|
||||
<property name="label">gtk-disconnect</property>
|
||||
|
|
@ -981,6 +1050,17 @@
|
|||
<signal name="activate" handler="linphone_gtk_show_assistant" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="audio_assistant_item">
|
||||
<property name="label" translatable="yes">Audio assistant</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="image">image21</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="linphone_gtk_show_audio_assistant" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -1109,6 +1189,12 @@
|
|||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
|
@ -1547,8 +1633,8 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="proxy_refresh_button">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="relief">none</property>
|
||||
|
|
@ -1618,7 +1704,7 @@
|
|||
<object class="GtkTable" id="table1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="n_rows">4</property>
|
||||
<property name="n_rows">5</property>
|
||||
<property name="n_columns">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label8">
|
||||
|
|
@ -1640,13 +1726,12 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label13">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Internet connection:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
|
@ -1684,7 +1769,6 @@
|
|||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="login_internet_kind">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="model">model4</property>
|
||||
<property name="active">0</property>
|
||||
|
|
@ -1699,8 +1783,8 @@
|
|||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
|
@ -1715,8 +1799,34 @@
|
|||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="userid">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">UserID</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="login_userid">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">•</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="secondary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">True</property>
|
||||
<property name="secondary_icon_sensitive">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
|
@ -1762,6 +1872,9 @@
|
|||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
|
|
@ -1838,59 +1951,6 @@
|
|||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="model1">
|
||||
<columns>
|
||||
<!-- column-name gchararray -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">All users</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Online users</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkListStore" id="model2">
|
||||
<columns>
|
||||
<!-- column-name gchararray -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">ADSL</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Fiber Channel</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkListStore" id="model3">
|
||||
<columns>
|
||||
<!-- column-name gchararray -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Default</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkListStore" id="model4">
|
||||
<columns>
|
||||
<!-- column-name gchararray -->
|
||||
<column type="gchararray"/>
|
||||
</columns>
|
||||
<data>
|
||||
<row>
|
||||
<col id="0" translatable="yes">ADSL</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Fiber Channel</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkImage" id="remove_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue