diff --git a/.cproject b/.cproject index 63cf57632..8a879f8a7 100644 --- a/.cproject +++ b/.cproject @@ -22,7 +22,7 @@ - + @@ -35,9 +35,12 @@ - - - + + + + + + @@ -48,8 +51,10 @@ - - + + + + @@ -198,4 +203,6 @@ + + diff --git a/.gitignore b/.gitignore index a06368361..6157903ce 100644 --- a/.gitignore +++ b/.gitignore @@ -52,14 +52,24 @@ coreapi/help/registration coreapi/test_ecc coreapi/test_lsd gtk/version_date.h - daemon/linphone-daemon daemon/linphone-daemon-pipetest -tools/lpc2xml_test -tools/xml2lpc_test *.la *.lo *.deps *.libs share/certdata.txt coreapi/test_numbers +specs.c +*.orig +*.rej +*.kdev4 +*.swp +.deps +.libs +coreapi/help/notify +share/fresh-rootca.pem +tester/liblinphone_tester +tools/lp-gen-wrappers +tools/lpc2xml_test +tools/xml2lpc_test \ No newline at end of file diff --git a/.project b/.project index dcc5fd75c..b1cfb8223 100644 --- a/.project +++ b/.project @@ -23,7 +23,7 @@ org.eclipse.cdt.make.core.buildArguments - CFLAGS="-g -Werror -Wall" CXXFLAGS="-g" + CFLAGS="-g -Werror -Wall" CXXFLAGS="-g" V=1 org.eclipse.cdt.make.core.buildCommand diff --git a/COPYING b/COPYING index d60c31a97..b18ab0474 100644 --- a/COPYING +++ b/COPYING @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest diff --git a/Makefile.am b/Makefile.am index d4e2be854..7de47e2c4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,8 +4,7 @@ ACLOCAL_AMFLAGS = -I m4 $(ACLOCAL_MACOS_FLAGS) SUBDIRS = build m4 pixmaps po @ORTP_DIR@ @MS2_DIR@ \ - coreapi console gtk share scripts tools daemon - + coreapi console gtk share scripts tools daemon tester include ACLOCAL_FLAGS=-I$(top_srcdir)/m4 @@ -37,7 +36,7 @@ SDK_EXCLUDED= \ GTK_PREFIX=/ GTK_THEME=Outcrop -GTK_FILELIST=gtk+-2.22.1.filelist +GTK_FILELIST=gtk+-2.24.8.filelist GTK_FILELIST_PATH=$(abs_top_srcdir)/$(GTK_FILELIST) LINPHONEDEPS_FILELIST=linphone-deps.filelist WINBINDIST_FILES=`cat $(abs_top_srcdir)/$(LINPHONEDEPS_FILELIST)` @@ -101,31 +100,33 @@ endif other-cherrypick: cd $(GTK_PREFIX) && \ for file in $(WINBINDIST_FILES) ; do \ - if test -d $$file; then \ + if test -d $(prefix)/$$file; then \ $(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/$$file ;\ else \ - cp $$file $(INSTALLDIR_WITH_PREFIX)/$$file ;\ + cp $(prefix)/$$file $(INSTALLDIR_WITH_PREFIX)/$$file ;\ fi \ done - cp /mingw/bin/libgcc_s*.dll \ - /mingw/bin/libstdc++-6.dll \ - /mingw/bin/libintl-8.dll \ - /mingw/bin/libiconv-2.dll \ - /mingw/bin/pthreadGC2.dll \ - $(INSTALLDIR_WITH_PREFIX)/bin/. + if test -d /mingw/bin ; then \ + cp /mingw/bin/libgcc_s*.dll \ + /mingw/bin/libstdc++-6.dll \ + /mingw/bin/libintl-8.dll \ + /mingw/bin/libiconv-2.dll \ + /mingw/bin/pthreadGC2.dll \ + $(INSTALLDIR_WITH_PREFIX)/bin/. ;\ + fi gtk-cherrypick: cd $(GTK_PREFIX) && \ for file in `cat $(GTK_FILELIST_PATH)` ; do \ - if test -d $$file; then \ + if test -d $(prefix)/$$file; then \ $(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/$$file ;\ else \ - cp $$file $(INSTALLDIR_WITH_PREFIX)/$$file ;\ + cp $(prefix)/$$file $(INSTALLDIR_WITH_PREFIX)/$$file ;\ fi \ done && \ $(MKDIR_P) $(INSTALLDIR_WITH_PREFIX)/share/themes && \ - cp -rf share/themes/$(GTK_THEME) $(INSTALLDIR_WITH_PREFIX)/share/themes/. + cp -rf $(prefix)/share/themes/$(GTK_THEME) $(INSTALLDIR_WITH_PREFIX)/share/themes/. zip: rm -f $(ZIPFILE) @@ -230,6 +231,6 @@ bundle: $(LIBICONV_HACK) clean-local: rm -rf $(BUNDLEDIR) discovery: - touch specs.cpp + touch specs.c $(CC) --include $(top_builddir)/config.h \ - $(TUNNEL_CFLAGS) $(CFLAGS) $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) -E -P -v -dD specs.cpp + $(TUNNEL_CFLAGS) $(CFLAGS) $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) $(SIPSTACK_CFLAGS) $(CUNIT_CFLAGS) -E -P -v -dD specs.c diff --git a/NEWS b/NEWS index e1a271db1..8797315b0 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,17 @@ +linphone-3.7...?? + Liblinphone level improvements thanks to belle-sip new SIP stack: + * multiple SIP transports simualtaneously now allowed + * IP dual stack: can use IPv6 and IPv4 simultaneously + * fully asynchronous behavior: no more lengthly DNS or connections + * +sip.instance parameter (RFC5626) + * alias parameter (RFC5923) + * better management of network disconnections + * SIP/TLS handled through lightweighted polarssl library (instead of openssl) + * SIP transaction state machines improved (RFC6026) + * Privacy API (RFC3323, RFC3325) + * Full support of rich presence in (RFC4480) + + linphone-3.6.1 -- June 17, 2013 * fix memory leak with some video cameras on windows. diff --git a/README b/README index c4a559418..8913f1205 100644 --- a/README +++ b/README @@ -8,9 +8,9 @@ This is Linphone, a free (GPL) video softphone based on the SIP protocol. - intltool - you need at least: - - libosip2>=3.5.0 - - libeXosip2>=3.5.0 + - belle-sip>=1.0.0 - speex>=1.2.0 (including libspeexdsp part) + - libxml2 + if you want the gtk/glade interface: - libgtk >=2.16.0 @@ -33,11 +33,11 @@ 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 libvxl1-dev libgl1-mesa-dev libglew1.6-dev libv4l-dev + $ 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 + for optional library - $ sudo apt-get install libreadline-dev libgsm1-dev libtheora-dev libsoup2.4-dev libsqlite3-dev libupnp4-dev - + $ sudo apt-get install libreadline-dev libgsm1-dev libtheora-dev libsoup2.4-dev libsqlite3-dev libupnp4-dev + + Install srtp (optional) for call encryption : $ git clone git://git.linphone.org/srtp.git $ cd srtp && autoconf && ./configure && make diff --git a/README.macos b/README.macos index e2f1593bd..1713b7968 100644 --- a/README.macos +++ b/README.macos @@ -7,17 +7,17 @@ You need: - Macports: http://www.macports.org/ Download and install macports using its user friendly installer. -- In order to enable generation of bundle for multiple macos version it is recommended to edit /opt/local/etc/macports/macports.conf to add the - following line: - macosx_deployment_target 10.6 +- In order to enable generation of bundle for multiple macos version and 32 bit processors, it is recommended to: + 1) edit /opt/local/etc/macports/macports.conf to add the following line: + macosx_deployment_target 10.6 + 2) edit /opt/local/etc/macports/variants.conf to add the following line: + +universal - Install build time dependencies $ sudo port install automake autoconf libtool intltool - Install some linphone dependencies with macports $ sudo port install speex - $ sudo port install libosip2 # WARNING: currently outdated in macport - $ sudo port install libeXosip2 #WARNING: currently outdated in macport $ sudo port install ffmpeg-devel -gpl2 $ sudo port install libvpx $ sudo port install readline @@ -36,6 +36,22 @@ You need: The softwares below 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" + +- Install polarssl (encryption library used by belle-sip) + $ git clone git://git.linphone.org/polarssl.git -b linphone + $ cd polarssl + $ ./autogen.sh && ./configure --prefix=/opt/local && make + $ sudo make install + +- Install belle-sip (sip stack) + $ git clone git://git.linphone.org/belle-sip.git + $ cd belle-sip + $ ./autogen.sh && ./configure --prefix=/opt/local && make + $ sudo make install - Install srtp (optional) for call encryption $ sudo port install srtp @@ -72,7 +88,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 && make + $ ./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 diff --git a/README.mingw b/README.mingw index be45614f2..cb1f60c01 100644 --- a/README.mingw +++ b/README.mingw @@ -26,7 +26,7 @@ Download lastest linphone-deps-win32 zip from http://download.savannah.gnu.org/releases-noredirect/linphone/misc using your browser. -Download lastest gtk+2 win32 bundle from http://www.gtk.org +Download lastest gtk+-2.24.10 win32 _bundle_ from http://www.gtk.org Install all these three package in /: @@ -65,23 +65,19 @@ WARNING: During the build, windows might slow down suddenly. Using ctl+alt+del t 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. -#Compile and install tunnel (optional, available under proprietary licensing) - -cd tunnel && ./autogen.sh && ./configure --prefix=/usr --enable-shared --disable-static && make && make install - #Build linphone itself: #run autogen.sh after a git checkout or update ./autogen.sh -./configure --prefix=/opt/linphone --enable-shared --disable-static +./configure --prefix=/usr --enable-shared --disable-static #note: in order to use the tunnel, append --enable-tunnel to the configure line above. #compile: make -#now install to /opt/linphone, required for compilation of plugins. +#now install to /usr, required for compilation of plugins. make install @@ -100,7 +96,7 @@ make setup.exe #build plugins cd mediastreamer2/plugins/msx264 ./autogen.sh -PKG_CONFIG_PATH=/opt/linphone/lib/pkgconfig ./configure --prefix=/opt/linphone --enable-shared --disable-static +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 @@ -109,7 +105,7 @@ 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=/opt/linphone/lib/pkgconfig ./configure --prefix=/opt/linphone --enable-shared --disable-static +PKG_CONFIG_PATH=/usr/lib/pkgconfig ./configure --prefix=/usr --enable-shared --disable-static make #make a binary zip of this plugin make zip @@ -125,13 +121,15 @@ These notes are useful if you want to upgrade part of the software that is inclu linphone-deps packages. List of software included in linphone-deps: -libosip2 (compiled) -libeXosip2 (compiled) +antlr3c (compiled) +polarssl (compiled +belle-sip (compiled) +libsrtp (compiled) libavcodec, libavutil, libavformat, libavdevice, libswscale (compiled, all these from ffmpeg) libtheora (from the web) libx264 (compiled from the version distributed from linphone's web site) libogg (from the web) -libspeex, libspeexdsp (compiled, statically to workaround a dll-related crash) +libspeex, libspeexdsp (compiled) libgnutls (from the web) libgsm (from the web) libxml2 (compiled) @@ -142,6 +140,45 @@ Remarks: For every package compiled that goes into linphone-deps, .la files (libtool files) must be removed to avoid libtool errors. When running "make install DESTDIR=", somepath must be absolute and should not contain any ~ or space. +- building antlr3c + * download the sources with: + $ git clone -b linphone git://git.linphone.org/antlr3.git + * compile and install + $ cd runtime/C + $ ./autogen.sh + $ ./configure --prefix=/usr --enable-shared --disable-static + $ make + $ make install + $ make install DESTDIR=/home//antlr3c-install + $ cp + +- building polarssl + * download the sources with: + $ git clone -b linphone git://git.linphone.org/polarssl.git + * compile and install: + $ cd polarssl + $ make lib SHARED=1 WINDOWS=1 + $ make install DESTDIR=/usr + $ make install DESTDIR=/home//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//belle-sip-install + +- building libsrtp + * download the sources with + $ git clone git://git.linphone.org/srtp.git + * compile with + $ autoconf + $ ./configure --prefix=/usr + $ make libsrtp.a + $ make install + $ make install DESTDIR=/home//libsrtp-install + - building sqlite3 * download the sources on the following website: http://www.sqlite.org/download.html (choose the sqlite-autoconf-3XXX.tar.gz) diff --git a/build/android/Android-no-neon.mk b/build/android/Android-no-neon.mk deleted file mode 100644 index 39818fbf4..000000000 --- a/build/android/Android-no-neon.mk +++ /dev/null @@ -1,50 +0,0 @@ -## -## Android.mk -Android build script- -## -## -## Copyright (C) 2010 Belledonne Communications, Grenoble, France -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -## - -LOCAL_PATH:= $(call my-dir)/../../coreapi - -include $(CLEAR_VARS) - -include $(linphone-root-dir)/submodules/linphone/build/android/common.mk - -ifeq ($(LINPHONE_VIDEO),1) -LOCAL_SHARED_LIBRARIES += \ - libavcodecnoneon \ - libswscale \ - libavcore \ - libavutil -endif - -LOCAL_MODULE := liblinphonenoneon -ifeq ($(TARGET_ARCH_ABI),armeabi) -LOCAL_MODULE_FILENAME := liblinphonearmv5noneon -endif -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -LOCAL_MODULE_FILENAME := liblinphonearmv7noneon -endif -ifeq ($(TARGET_ARCH_ABI),x86) -LOCAL_MODULE_FILENAME := liblinphonex86 -endif - -include $(BUILD_SHARED_LIBRARY) - -$(call import-module,android/cpufeatures) - diff --git a/build/android/Android.mk b/build/android/Android.mk index 0dc0bd041..e9c9fa1f6 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -23,20 +23,215 @@ LOCAL_PATH:= $(call my-dir)/../../coreapi include $(CLEAR_VARS) -include $(linphone-root-dir)/submodules/linphone/build/android/common.mk +LOCAL_CPP_EXTENSION := .cc -ifeq ($(LINPHONE_VIDEO),1) +LOCAL_SRC_FILES := \ + linphonecore.c \ + misc.c \ + enum.c \ + presence.c \ + proxy.c \ + friend.c \ + authentication.c \ + lpconfig.c \ + chat.c \ + sipsetup.c \ + siplogin.c \ + address.c \ + linphonecore_jni.cc \ + 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_impl.c \ + bellesip_sal/sal_op_message.c \ + bellesip_sal/sal_op_presence.c \ + bellesip_sal/sal_op_registration.c \ + bellesip_sal/sal_op_publish.c \ + bellesip_sal/sal_op_info.c \ + bellesip_sal/sal_op_events.c \ + bellesip_sal/sal_sdp.c \ + sal.c \ + offeranswer.c \ + callbacks.c \ + linphonecall.c \ + conference.c \ + ec-calibrator.c \ + linphone_tunnel_config.c \ + message_storage.c \ + info.c \ + event.c + +ifndef LINPHONE_VERSION +LINPHONE_VERSION = "Devel" +endif + +LOCAL_CFLAGS += \ + -D_BYTE_ORDER=_LITTLE_ENDIAN \ + -DORTP_INET6 \ + -DINET6 \ + -DENABLE_TRACE \ + -DHAVE_CONFIG_H \ + -DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \ + -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ + -DUSE_BELLESIP + +LOCAL_CFLAGS += -DIN_LINPHONE + +ifeq ($(_BUILD_VIDEO),1) +LOCAL_CFLAGS += -DVIDEO_ENABLED +ifeq ($(BUILD_X264),1) +LOCAL_CFLAGS += -DHAVE_X264 +endif +endif + +ifeq ($(BUILD_CONTACT_HEADER),1) +LOCAL_CFLAGS += -DSAL_OP_CALL_FORCE_CONTACT_IN_RINGING +endif + +ifeq ($(USE_JAVAH),1) +LOCAL_CFLAGS += -DUSE_JAVAH +endif + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../build/android \ + $(LOCAL_PATH)/../oRTP/include \ + $(LOCAL_PATH)/../mediastreamer2/include \ + $(LOCAL_PATH)/../../belle-sip/include \ + $(LOCAL_PATH)/../../../gen \ + $(LOCAL_PATH)/../../externals/libxml2/include \ + $(LOCAL_PATH)/../../externals/build/libxml2 + +LOCAL_LDLIBS += -llog -ldl + +LOCAL_STATIC_LIBRARIES := \ + cpufeatures \ + libmediastreamer2 \ + libortp \ + libbellesip \ + libgsm \ + liblpxml2 + + +ifeq ($(BUILD_TUNNEL),1) +LOCAL_CFLAGS +=-DTUNNEL_ENABLED +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../tunnel/include $(LOCAL_PATH)/../../tunnel/src +LOCAL_SRC_FILES += linphone_tunnel.cc TunnelManager.cc +LOCAL_STATIC_LIBRARIES += libtunnelclient +else +LOCAL_SRC_FILES += linphone_tunnel_stubs.c +endif + + +_BUILD_AMR=0 +ifneq ($(BUILD_AMRNB), 0) +_BUILD_AMR=1 +endif + +ifneq ($(BUILD_AMRWB), 0) +_BUILD_AMR=1 +endif + +ifneq ($(_BUILD_AMR), 0) +LOCAL_CFLAGS += -DHAVE_AMR +LOCAL_STATIC_LIBRARIES += \ + libmsamr \ + libopencoreamr +endif + +ifneq ($(BUILD_AMRWB), 0) +LOCAL_STATIC_LIBRARIES += \ + libvoamrwbenc +endif + + +ifeq ($(BUILD_SILK),1) +LOCAL_CFLAGS += -DHAVE_SILK +LOCAL_STATIC_LIBRARIES += libmssilk +endif + +ifeq ($(BUILD_WEBRTC_ISAC),1) +LOCAL_CFLAGS += -DHAVE_ISAC +LOCAL_STATIC_LIBRARIES += libwebrtc_isacfix_neon +LOCAL_STATIC_LIBRARIES += libwebrtc_spl libwebrtc_isacfix libmsisac +endif + +ifeq ($(BUILD_G729),1) +LOCAL_CFLAGS += -DHAVE_G729 +LOCAL_STATIC_LIBRARIES += libbcg729 libmsbcg729 +endif + +ifeq ($(_BUILD_VIDEO),1) +LOCAL_LDLIBS += -lGLESv2 +LOCAL_STATIC_LIBRARIES += libvpx +ifeq ($(BUILD_X264),1) +LOCAL_STATIC_LIBRARIES += \ + libmsx264 \ + libx264 +endif +endif + +ifeq ($(BUILD_UPNP),1) +LOCAL_CFLAGS += -DBUILD_UPNP +LOCAL_SRC_FILES += upnp.c +endif + +LOCAL_STATIC_LIBRARIES += libspeex + +ifeq ($(BUILD_SRTP), 1) + LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE) +endif + +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +LOCAL_CFLAGS += -DHAVE_ILBC=1 +LOCAL_STATIC_LIBRARIES += libmsilbc +endif + +LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES) +LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS) +LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES) + +ifeq ($(BUILD_GPLV3_ZRTP),1) + LOCAL_SHARED_LIBRARIES += libssl-linphone libcrypto-linphone + LOCAL_SHARED_LIBRARIES += libzrtpcpp +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 + +endif + +ifeq ($(BUILD_SQLITE),1) +LOCAL_CFLAGS += -DMSG_STORAGE_ENABLED +LOCAL_STATIC_LIBRARIES += liblinsqlite +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/../../externals/sqlite3/ +endif + +ifeq ($(BUILD_OPUS),1) +LOCAL_STATIC_LIBRARIES += libopus +endif +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) +LOCAL_EXPORT_CFLAGS := $(LOCAL_CFLAGS) + +ifeq ($(_BUILD_VIDEO),1) LOCAL_SHARED_LIBRARIES += \ - libavcodec \ - libswscale \ - libavcore \ - libavutil + libavcodec-linphone \ + libswscale-linphone \ + libavutil-linphone endif LOCAL_MODULE := liblinphone -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -LOCAL_MODULE_FILENAME := liblinphonearmv7 -endif +LOCAL_MODULE_FILENAME := liblinphone-$(TARGET_ARCH_ABI) include $(BUILD_SHARED_LIBRARY) diff --git a/build/android/common.mk b/build/android/common.mk deleted file mode 100644 index d0bf70cad..000000000 --- a/build/android/common.mk +++ /dev/null @@ -1,205 +0,0 @@ -## -## Android.mk -Android build script- -## -## -## Copyright (C) 2010 Belledonne Communications, Grenoble, France -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -## - -LOCAL_CPP_EXTENSION := .cc - -LOCAL_SRC_FILES := \ - linphonecore.c \ - misc.c \ - enum.c \ - presence.c \ - proxy.c \ - friend.c \ - authentication.c \ - lpconfig.c \ - chat.c \ - sipsetup.c \ - siplogin.c \ - address.c \ - linphonecore_jni.cc \ - sal.c \ - sal_eXosip2.c \ - sal_eXosip2_presence.c \ - sal_eXosip2_sdp.c \ - offeranswer.c \ - callbacks.c \ - linphonecall.c \ - conference.c \ - ec-calibrator.c \ - linphone_tunnel_config.c \ - message_storage.c - -ifndef LINPHONE_VERSION -LINPHONE_VERSION = "Devel" -endif - -LOCAL_CFLAGS += \ - -D_BYTE_ORDER=_LITTLE_ENDIAN \ - -DORTP_INET6 \ - -DINET6 \ - -DOSIP_MT \ - -DENABLE_TRACE \ - -DHAVE_CONFIG_H \ - -DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \ - -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ - -LOCAL_CFLAGS += -DIN_LINPHONE - -ifeq ($(LINPHONE_VIDEO),1) -LOCAL_CFLAGS += -DVIDEO_ENABLED -ifeq ($(BUILD_X264),1) -LOCAL_CFLAGS += -DHAVE_X264 -endif -endif - -ifeq ($(USE_JAVAH),1) -LOCAL_CFLAGS += -DUSE_JAVAH -endif - -LOCAL_C_INCLUDES += \ - $(LOCAL_PATH) \ - $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/../build/android \ - $(LOCAL_PATH)/../oRTP/include \ - $(LOCAL_PATH)/../mediastreamer2/include \ - $(LOCAL_PATH)/../../externals/exosip/include \ - $(LOCAL_PATH)/../../externals/osip/include \ - $(LOCAL_PATH)/../../../gen - -LOCAL_LDLIBS += -llog -ldl - - - -LOCAL_STATIC_LIBRARIES := \ - cpufeatures \ - libmediastreamer2 \ - libortp \ - libeXosip2 \ - libosip2 \ - libgsm - -ifeq ($(BUILD_REMOTE_PROVISIONING),1) -LOCAL_STATIC_LIBRARIES += \ - libxml2lpc \ - liblpc2xml \ - liblpxml2 -endif - -ifeq ($(BUILD_TUNNEL),1) -LOCAL_CFLAGS +=-DTUNNEL_ENABLED -LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../tunnel/include $(LOCAL_PATH)/../../tunnel/src -LOCAL_SRC_FILES += linphone_tunnel.cc TunnelManager.cc -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -LOCAL_SHARED_LIBRARIES += libtunnelclient -else -LOCAL_STATIC_LIBRARIES += libtunnelclient -endif -else -LOCAL_SRC_FILES += linphone_tunnel_stubs.c -endif - - -_BUILD_AMR=0 -ifneq ($(BUILD_AMRNB), 0) -_BUILD_AMR=1 -endif - -ifneq ($(BUILD_AMRWB), 0) -_BUILD_AMR=1 -endif - -ifneq ($(_BUILD_AMR), 0) -LOCAL_CFLAGS += -DHAVE_AMR -LOCAL_STATIC_LIBRARIES += \ - libmsamr \ - libopencoreamr -endif - -ifneq ($(BUILD_AMRWB), 0) -LOCAL_STATIC_LIBRARIES += \ - libvoamrwbenc -endif - - -ifeq ($(BUILD_SILK),1) -LOCAL_CFLAGS += -DHAVE_SILK -LOCAL_STATIC_LIBRARIES += libmssilk -endif - -ifeq ($(BUILD_G729),1) -LOCAL_CFLAGS += -DHAVE_G729 -LOCAL_SHARED_LIBRARIES += libbcg729 -LOCAL_STATIC_LIBRARIES += libmsbcg729 -endif - -ifeq ($(LINPHONE_VIDEO),1) -LOCAL_LDLIBS += -lGLESv2 -LOCAL_STATIC_LIBRARIES += libvpx -ifeq ($(BUILD_X264),1) -LOCAL_STATIC_LIBRARIES += \ - libmsx264 \ - libx264 -endif -endif - -ifeq ($(BUILD_UPNP),1) -LOCAL_CFLAGS += -DBUILD_UPNP -LOCAL_SRC_FILES += upnp.c -endif - -LOCAL_STATIC_LIBRARIES += libspeex - -ifeq ($(BUILD_SRTP), 1) - LOCAL_C_INCLUDES += $(SRTP_C_INCLUDE) -endif - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) -LOCAL_CFLAGS += -DHAVE_ILBC=1 -LOCAL_STATIC_LIBRARIES += libmsilbc -endif - -LOCAL_C_INCLUDES += $(LIBLINPHONE_EXTENDED_C_INCLUDES) -LOCAL_WHOLE_STATIC_LIBRARIES += $(LIBLINPHONE_EXTENDED_STATIC_LIBS) -LOCAL_SRC_FILES += $(LIBLINPHONE_EXTENDED_SRC_FILES) - -ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) - LOCAL_SHARED_LIBRARIES += liblinssl liblincrypto - ifeq ($(BUILD_GPLV3_ZRTP),1) - LOCAL_SHARED_LIBRARIES += libzrtpcpp - endif - - ifeq ($(BUILD_SRTP),1) - LOCAL_SHARED_LIBRARIES += libsrtp - endif -else - LOCAL_LDLIBS += -lz - #LOCAL_STATIC_LIBRARIES += libz libdl - LOCAL_STATIC_LIBRARIES += \ - libssl-static libcrypto-static - ifeq ($(BUILD_GPLV3_ZRTP),1) - LOCAL_STATIC_LIBRARIES += libzrtpcpp-static - endif - - ifeq ($(BUILD_SRTP),1) - LOCAL_STATIC_LIBRARIES += libsrtp-static - endif -endif - diff --git a/build/android/config.h b/build/android/config.h index 22321c5f7..0842116ab 100644 --- a/build/android/config.h +++ b/build/android/config.h @@ -38,19 +38,19 @@ /* #def HAVE_EXOSIP_DSCP */ /* Defined when eXosip_get_version is available */ -#define HAVE_EXOSIP_GET_VERSION +/* #undef HAVE_EXOSIP_GET_VERSION */ /* Defined when eXosip_reset_transports is available */ -#define HAVE_EXOSIP_RESET_TRANSPORTS +/* #undef HAVE_EXOSIP_RESET_TRANSPORTS */ /* Defined when eXosip_tls_verify_certificate is available */ -#define HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE +/* #undef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE */ /* Defined when eXosip_tls_verify_certificate is available */ /* #undef HAVE_EXOSIP_TLS_VERIFY_CN */ /* Defined when eXosip_get_socket is available */ -#define HAVE_EXOSIP_TRYLOCK +/* #undef HAVE_EXOSIP_TRYLOCK */ /* If present, the getenv function allows fim to read environment variables. */ diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk new file mode 100644 index 000000000..5d9c7a469 --- /dev/null +++ b/build/android/liblinphone_tester.mk @@ -0,0 +1,33 @@ +LOCAL_PATH := $(call my-dir)/../../tester + +common_SRC_FILES := \ + call_tester.c \ + liblinphone_tester.c \ + message_tester.c \ + presence_tester.c \ + register_tester.c \ + setup_tester.c \ + upnp_tester.c \ + eventapi_tester.c + +common_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../coreapi \ + $(LOCAL_PATH)/../oRTP/include \ + $(LOCAL_PATH)/../mediastreamer2/include + + +include $(CLEAR_VARS) + +LOCAL_MODULE := liblinphone_tester +LOCAL_MODULE_FILENAME := liblinphone_tester-$(TARGET_ARCH_ABI) +LOCAL_SRC_FILES += $(common_SRC_FILES) +LOCAL_C_INCLUDES = $(common_C_INCLUDES) +LOCAL_CFLAGS = -DIN_LINPHONE +LOCAL_LDLIBS := -llog + +LOCAL_SHARED_LIBRARIES := cunit liblinphone +include $(BUILD_SHARED_LIBRARY) + +#end diff --git a/build/android/lpc2xml.mk b/build/android/lpc2xml.mk deleted file mode 100644 index d93be9b79..000000000 --- a/build/android/lpc2xml.mk +++ /dev/null @@ -1,47 +0,0 @@ -## -## Android.mk -Android build script- -## -## -## Copyright (C) 2013 Belledonne Communications, Grenoble, France -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -## - -LOCAL_PATH:= $(call my-dir)/../../tools - -include $(CLEAR_VARS) - -LOCAL_CPP_EXTENSION := .cc - -LOCAL_SRC_FILES := \ - lpc2xml.c \ - lpc2xml_jni.cc \ - -LOCAL_CFLAGS += -DIN_LINPHONE - -LOCAL_C_INCLUDES = \ - $(LOCAL_PATH)/../coreapi \ - $(LOCAL_PATH)/../oRTP/include \ - $(LOCAL_PATH)/../mediastreamer2/include \ - $(LOCAL_PATH)/../../externals/libxml2/include \ - $(LOCAL_PATH)/../../externals/build/libxml2 \ - -LOCAL_SHARED_LIBRARIES = \ -# liblinphonenoneon \ -# liblinphone \ - -LOCAL_MODULE := liblpc2xml - -include $(BUILD_STATIC_LIBRARY) diff --git a/build/android/xml2lpc.mk b/build/android/xml2lpc.mk deleted file mode 100644 index 55e4a03a0..000000000 --- a/build/android/xml2lpc.mk +++ /dev/null @@ -1,47 +0,0 @@ -## -## Android.mk -Android build script- -## -## -## Copyright (C) 2013 Belledonne Communications, Grenoble, France -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -## - -LOCAL_PATH:= $(call my-dir)/../../tools - -include $(CLEAR_VARS) - -LOCAL_CPP_EXTENSION := .cc - -LOCAL_SRC_FILES := \ - xml2lpc.c \ - xml2lpc_jni.cc \ - -LOCAL_CFLAGS += -DIN_LINPHONE - -LOCAL_C_INCLUDES = \ - $(LOCAL_PATH)/../coreapi \ - $(LOCAL_PATH)/../oRTP/include \ - $(LOCAL_PATH)/../mediastreamer2/include \ - $(LOCAL_PATH)/../../externals/libxml2/include \ - $(LOCAL_PATH)/../../externals/build/libxml2 \ - -LOCAL_SHARED_LIBRARIES = \ -# liblinphonenoneon \ -# liblinphone \ - -LOCAL_MODULE := libxml2lpc - -include $(BUILD_STATIC_LIBRARY) diff --git a/build/macos/linphone.bundle b/build/macos/linphone.bundle index 6985bfb29..780b73e1c 100644 --- a/build/macos/linphone.bundle +++ b/build/macos/linphone.bundle @@ -15,7 +15,8 @@ /opt/local ${env:LINPHONE_INSTALL_PREFIX} ${env:MS2_PLUGINS_INSTALL_PREFIX} - /opt/local + + /usr/local + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml.cs new file mode 100644 index 000000000..5052b5a01 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml.cs @@ -0,0 +1,234 @@ +using System; +using System.Diagnostics; +using System.Resources; +using System.Windows; +using System.Windows.Markup; +using System.Windows.Navigation; +using Microsoft.Phone.Controls; +using Microsoft.Phone.Shell; +using LibLinphoneTester_wp8.Resources; +using linphone_tester_native; + +namespace LibLinphoneTester_wp8 +{ + public partial class App : Application + { + /// + /// Provides easy access to the root frame of the Phone Application. + /// + /// The root frame of the Phone Application. + public static PhoneApplicationFrame RootFrame { get; private set; } + + /// + /// Constructor for the Application object. + /// + public App() + { + // Global handler for uncaught exceptions. + UnhandledException += Application_UnhandledException; + + // Standard XAML initialization + InitializeComponent(); + + // Phone-specific initialization + InitializePhoneApplication(); + + // Language display initialization + InitializeLanguage(); + + // Show graphics profiling information while debugging. + if (Debugger.IsAttached) + { + // Display the current frame rate counters. + Application.Current.Host.Settings.EnableFrameRateCounter = true; + + // Show the areas of the app that are being redrawn in each frame. + //Application.Current.Host.Settings.EnableRedrawRegions = true; + + // Enable non-production analysis visualization mode, + // which shows areas of a page that are handed off to GPU with a colored overlay. + //Application.Current.Host.Settings.EnableCacheVisualization = true; + + // Prevent the screen from turning off while under the debugger by disabling + // the application's idle detection. + // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run + // and consume battery power when the user is not using the phone. + PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled; + } + + tester = new LinphoneTesterNative(); + suite = null; + } + + // Code to execute when the application is launching (eg, from Start) + // This code will not execute when the application is reactivated + private void Application_Launching(object sender, LaunchingEventArgs e) + { + } + + // Code to execute when the application is activated (brought to foreground) + // This code will not execute when the application is first launched + private void Application_Activated(object sender, ActivatedEventArgs e) + { + } + + // Code to execute when the application is deactivated (sent to background) + // This code will not execute when the application is closing + private void Application_Deactivated(object sender, DeactivatedEventArgs e) + { + } + + // Code to execute when the application is closing (eg, user hit Back) + // This code will not execute when the application is deactivated + private void Application_Closing(object sender, ClosingEventArgs e) + { + } + + // Code to execute if a navigation fails + private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) + { + if (Debugger.IsAttached) + { + // A navigation has failed; break into the debugger + Debugger.Break(); + } + } + + // Code to execute on Unhandled Exceptions + private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) + { + if (Debugger.IsAttached) + { + // An unhandled exception has occurred; break into the debugger + Debugger.Break(); + } + } + + #region Phone application initialization + + // Avoid double-initialization + private bool phoneApplicationInitialized = false; + + // Do not add any additional code to this method + private void InitializePhoneApplication() + { + if (phoneApplicationInitialized) + return; + + // Create the frame but don't set it as RootVisual yet; this allows the splash + // screen to remain active until the application is ready to render. + RootFrame = new PhoneApplicationFrame(); + RootFrame.Navigated += CompleteInitializePhoneApplication; + + // Handle navigation failures + RootFrame.NavigationFailed += RootFrame_NavigationFailed; + + // Handle reset requests for clearing the backstack + RootFrame.Navigated += CheckForResetNavigation; + + // Ensure we don't initialize again + phoneApplicationInitialized = true; + } + + // Do not add any additional code to this method + private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e) + { + // Set the root visual to allow the application to render + if (RootVisual != RootFrame) + RootVisual = RootFrame; + + // Remove this handler since it is no longer needed + RootFrame.Navigated -= CompleteInitializePhoneApplication; + } + + private void CheckForResetNavigation(object sender, NavigationEventArgs e) + { + // If the app has received a 'reset' navigation, then we need to check + // on the next navigation to see if the page stack should be reset + if (e.NavigationMode == NavigationMode.Reset) + RootFrame.Navigated += ClearBackStackAfterReset; + } + + private void ClearBackStackAfterReset(object sender, NavigationEventArgs e) + { + // Unregister the event so it doesn't get called again + RootFrame.Navigated -= ClearBackStackAfterReset; + + // Only clear the stack for 'new' (forward) and 'refresh' navigations + if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh) + return; + + // For UI consistency, clear the entire page stack + while (RootFrame.RemoveBackEntry() != null) + { + ; // do nothing + } + } + + #endregion + + // Initialize the app's font and flow direction as defined in its localized resource strings. + // + // To ensure that the font of your application is aligned with its supported languages and that the + // FlowDirection for each of those languages follows its traditional direction, ResourceLanguage + // and ResourceFlowDirection should be initialized in each resx file to match these values with that + // file's culture. For example: + // + // AppResources.es-ES.resx + // ResourceLanguage's value should be "es-ES" + // ResourceFlowDirection's value should be "LeftToRight" + // + // AppResources.ar-SA.resx + // ResourceLanguage's value should be "ar-SA" + // ResourceFlowDirection's value should be "RightToLeft" + // + // For more info on localizing Windows Phone apps see http://go.microsoft.com/fwlink/?LinkId=262072. + // + private void InitializeLanguage() + { + try + { + // Set the font to match the display language defined by the + // ResourceLanguage resource string for each supported language. + // + // Fall back to the font of the neutral language if the Display + // language of the phone is not supported. + // + // If a compiler error is hit then ResourceLanguage is missing from + // the resource file. + RootFrame.Language = XmlLanguage.GetLanguage(AppResources.ResourceLanguage); + + // Set the FlowDirection of all elements under the root frame based + // on the ResourceFlowDirection resource string for each + // supported language. + // + // If a compiler error is hit then ResourceFlowDirection is missing from + // the resource file. + FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection); + RootFrame.FlowDirection = flow; + } + catch + { + // If an exception is caught here it is most likely due to either + // ResourceLangauge not being correctly set to a supported language + // code or ResourceFlowDirection is set to a value other than LeftToRight + // or RightToLeft. + + if (Debugger.IsAttached) + { + Debugger.Break(); + } + + throw; + } + } + + public bool suiteRunning() + { + return (suite != null) && (suite.running); + } + + public LinphoneTesterNative tester { get; set; } + public UnitTestSuite suite { get; set; } + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png new file mode 100644 index 000000000..f7d2e9780 Binary files /dev/null and b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png differ diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png new file mode 100644 index 000000000..7d95d4e08 Binary files /dev/null and b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png differ diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png new file mode 100644 index 000000000..e0c59ac01 Binary files /dev/null and b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png differ diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png new file mode 100644 index 000000000..e93b89d60 Binary files /dev/null and b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png differ diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png new file mode 100644 index 000000000..550b1b5e8 Binary files /dev/null and b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png differ diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png new file mode 100644 index 000000000..686e6b53f Binary files /dev/null and b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png differ diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png new file mode 100644 index 000000000..d4b5ede1b Binary files /dev/null and b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png differ diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc new file mode 100644 index 000000000..2fa8c43a3 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc @@ -0,0 +1,6 @@ +[net] +mtu=1300 + +[sip] +ping_with_options=0 +sip_random_port=1 \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc new file mode 100644 index 000000000..54a682401 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc @@ -0,0 +1,41 @@ +[sip] +sip_port=5092 +sip_tcp_port=5092 +sip_tls_port=5093 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=laure +userid=laure +passwd=secret +realm="sip.example.org" + + +[proxy_0] +reg_proxy=sip.example.org +reg_identity=sip:laure@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + + +[rtp] +audio_rtp_port=9010 +video_rtp_port=9012 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc new file mode 100644 index 000000000..65934c3f3 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc @@ -0,0 +1,45 @@ +[sip] +sip_port=5082 +sip_tcp_port=5082 +sip_tls_port=5083 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +incoming_calls_early_media=1 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm="sip.example.org" + + +[proxy_0] +reg_proxy=sip.example.org;transport=tcp +reg_route=sip.example.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=8072 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc new file mode 100644 index 000000000..56c96bc98 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc @@ -0,0 +1,47 @@ +[sip] +sip_port=5082 +sip_tcp_port=5082 +sip_tls_port=5083 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm="sip.example.org" + + +[proxy_0] +reg_proxy=sip.example.org;transport=tcp +reg_route=sip.example.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=8072 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc new file mode 100644 index 000000000..23705a733 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc @@ -0,0 +1,55 @@ +[sip] +sip_port=5072 +sip_tcp_port=5072 +sip_tls_port=5073 +default_proxy=0 + +[auth_info_0] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth.example.org" + +[auth_info_1] +username=pauline +userid=pauline +passwd=secret +realm="sip.example.org" + +[auth_info_2] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm="auth1.example.org" + +[auth_info_3] +username=marie +userid=marie +passwd=secret +realm="sip.example.org" + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tls +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_1] +reg_proxy=sip.example.org;transport=tcp +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_2] +reg_proxy=auth1.example.org +reg_identity=sip:liblinphone_tester@auth1.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + + diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/oldphone.wav b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/oldphone.wav new file mode 100644 index 000000000..7e99ecbf4 Binary files /dev/null and b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/oldphone.wav differ diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc new file mode 100644 index 000000000..4ff876cf7 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc @@ -0,0 +1,46 @@ +[sip] +sip_port=5072 +sip_tcp_port=5072 +sip_tls_port=5073 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm="sip.example.org" + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tls +reg_route=sip2.linphone.org;transport=tls +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +#[friend_0] +#url="Mariette" +#pol=accept +#subscribe=0 + +[rtp] +audio_rtp_port=8090 +video_rtp_port=8092 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ringback.wav b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ringback.wav new file mode 100644 index 000000000..21f4b5bfb Binary files /dev/null and b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ringback.wav differ diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj new file mode 100644 index 000000000..6ab7c0d58 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj @@ -0,0 +1,193 @@ + + + + Debug + AnyCPU + 10.0.20506 + 2.0 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90} + {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + LibLinphoneTester_wp8 + LibLinphoneTester_wp8 + WindowsPhone + v8.0 + $(TargetFrameworkVersion) + true + + + true + true + LibLinphoneTester_wp8_$(Configuration)_$(Platform).xap + Properties\AppManifest.xml + LibLinphoneTester_wp8.App + true + 11.0 + true + + + true + full + false + Bin\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + true + full + false + Bin\x86\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\x86\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + true + full + false + Bin\ARM\Debug + DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + pdbonly + true + Bin\ARM\Release + TRACE;SILVERLIGHT;WINDOWS_PHONE + true + true + prompt + 4 + + + + App.xaml + + + + MainPage.xaml + + + + True + True + AppResources.resx + + + TestCasePage.xaml + + + TestResultPage.xaml + + + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + + + + + + + + + + Designer + + + + + + PreserveNewest + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + PublicResXFileCodeGenerator + AppResources.Designer.cs + + + + + {5E94A00B-B14A-4E42-8284-8CB0EF099534} + LibLinphoneTester + + + + + + + + + Xcopy /I /Y $(ProjectDir)..\..\..\..\tester\*rc $(ProjectDir)Assets\ + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LocalizedStrings.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LocalizedStrings.cs new file mode 100644 index 000000000..e639982ad --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LocalizedStrings.cs @@ -0,0 +1,14 @@ +using LibLinphoneTester_wp8.Resources; + +namespace LibLinphoneTester_wp8 +{ + /// + /// Provides access to string resources. + /// + public class LocalizedStrings + { + private static AppResources _localizedResources = new AppResources(); + + public AppResources LocalizedResources { get { return _localizedResources; } } + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml new file mode 100644 index 000000000..c912857f9 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml.cs new file mode 100644 index 000000000..aa5307968 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Navigation; +using Microsoft.Phone.Controls; +using Microsoft.Phone.Shell; + +namespace LibLinphoneTester_wp8 +{ + public partial class MainPage : PhoneApplicationPage + { + public MainPage() + { + InitializeComponent(); + + var tester = (Application.Current as App).tester; + List source = new List(); + source.Add(new UnitTestSuiteName("ALL")); + for (int i = 0; i < tester.nbTestSuites(); i++) + { + source.Add(new UnitTestSuiteName(tester.testSuiteName(i))); + } + + Tests.ItemsSource = source; + } + + private void Tests_Tap(object sender, System.Windows.Input.GestureEventArgs e) + { + UnitTestSuiteName test = (sender as LongListSelector).SelectedItem as UnitTestSuiteName; + if (test == null) return; + if (test.Name == "ALL") + { + NavigationService.Navigate(new Uri("/TestResultPage.xaml?SuiteName=" + test.Name + "&Verbose=" + Verbose.IsChecked.GetValueOrDefault(), UriKind.Relative)); + } + else + { + NavigationService.Navigate(new Uri("/TestCasePage.xaml?SuiteName=" + test.Name + "&Verbose=" + Verbose.IsChecked.GetValueOrDefault(), UriKind.Relative)); + } + } + } + + public class UnitTestSuiteName + { + public string Name + { + get; + set; + } + + public UnitTestSuiteName(string name) + { + this.Name = name; + } + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml new file mode 100644 index 000000000..a95523275 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml @@ -0,0 +1,6 @@ + + + + diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0b87f1f9b --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Resources; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("LibLinphoneTester_wp8")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("LibLinphoneTester_wp8")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f1aad7a9-2083-4726-ab28-f57b1dd5891e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: NeutralResourcesLanguageAttribute("en-US")] diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml new file mode 100644 index 000000000..7ce78feb0 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml @@ -0,0 +1,48 @@ + + + + + Assets\ApplicationIcon.png + + + + + + + + + + + + + + Assets\Tiles\FlipCycleTileSmall.png + 0 + Assets\Tiles\FlipCycleTileMedium.png + LibLinphoneTester_wp8 + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs new file mode 100644 index 000000000..991c3a23d --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs @@ -0,0 +1,127 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.17626 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace LibLinphoneTester_wp8.Resources +{ + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class AppResources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal AppResources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager + { + get + { + if (object.ReferenceEquals(resourceMan, null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LibLinphoneTester_wp8.Resources.AppResources", typeof(AppResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to LeftToRight. + /// + public static string ResourceFlowDirection + { + get + { + return ResourceManager.GetString("ResourceFlowDirection", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to us-EN. + /// + public static string ResourceLanguage + { + get + { + return ResourceManager.GetString("ResourceLanguage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to MY APPLICATION. + /// + public static string ApplicationTitle + { + get + { + return ResourceManager.GetString("ApplicationTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to button. + /// + public static string AppBarButtonText + { + get + { + return ResourceManager.GetString("AppBarButtonText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to menu item. + /// + public static string AppBarMenuItemText + { + get + { + return ResourceManager.GetString("AppBarMenuItemText", resourceCulture); + } + } + } +} diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.resx b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.resx new file mode 100644 index 000000000..78837dc46 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.resx @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + LeftToRight + Controls the FlowDirection for all elements in the RootFrame. Set to the traditional direction of this resource file's language + + + en-US + Controls the Language and ensures that the font for all elements in the RootFrame aligns with the app's language. Set to the language code of this resource file's language. + + + MY APPLICATION + + + add + + + Menu Item + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml new file mode 100644 index 000000000..b6f2ea932 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs new file mode 100644 index 000000000..aae5f878b --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Navigation; +using Microsoft.Phone.Controls; +using Microsoft.Phone.Shell; + +namespace LibLinphoneTester_wp8 +{ + public partial class TestCasePage : PhoneApplicationPage + { + public TestCasePage() + { + InitializeComponent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + suiteName = NavigationContext.QueryString["SuiteName"]; + verbose = Convert.ToBoolean(NavigationContext.QueryString["Verbose"]); + var tester = (Application.Current as App).tester; + List source = new List(); + source.Add(new UnitTestCaseName("ALL")); + for (int i = 0; i < tester.nbTests(suiteName); i++) + { + source.Add(new UnitTestCaseName(tester.testName(suiteName, i))); + } + + Tests.ItemsSource = source; + } + + private void Tests_Tap(object sender, System.Windows.Input.GestureEventArgs e) + { + UnitTestCaseName test = (sender as LongListSelector).SelectedItem as UnitTestCaseName; + if (test == null) return; + if (!(Application.Current as App).suiteRunning()) + { + NavigationService.Navigate(new Uri("/TestResultPage.xaml?SuiteName=" + suiteName + "&CaseName=" + test.Name + "&Verbose=" + verbose, UriKind.Relative)); + } + } + + private string suiteName; + private bool verbose; + } + + public class UnitTestCaseName + { + public string Name + { + get; + set; + } + + public UnitTestCaseName(string name) + { + this.Name = name; + } + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml new file mode 100644 index 000000000..42f143fa0 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs new file mode 100644 index 000000000..129d2d833 --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Navigation; +using Microsoft.Phone.Controls; +using Microsoft.Phone.Shell; +using System.Threading.Tasks; +using linphone_tester_native; + +namespace LibLinphoneTester_wp8 +{ + public delegate void OutputDisplayDelegate(int level, String msg); + + public partial class TestResultPage : PhoneApplicationPage + { + public TestResultPage() + { + InitializeComponent(); + Browser.Navigate(new Uri("log.html", UriKind.Relative)); + } + + private void Browser_LoadCompleted(object sender, NavigationEventArgs e) + { + string suiteName = NavigationContext.QueryString["SuiteName"]; + string caseName; + if (NavigationContext.QueryString.ContainsKey("CaseName")) + { + caseName = NavigationContext.QueryString["CaseName"]; + } + else + { + caseName = "ALL"; + } + bool verbose = Convert.ToBoolean(NavigationContext.QueryString["Verbose"]); + var app = (Application.Current as App); + app.suite = new UnitTestSuite(suiteName, caseName, verbose, new OutputDisplayDelegate(OutputDisplay)); + app.suite.run(); + } + + public void OutputDisplay(int level, String msg) + { + this.Dispatcher.BeginInvoke(() => + { + msg = msg.Replace("\r\n", "\n"); + string[] lines = msg.Split('\n'); + bool insertNewLine = false; + foreach (string line in lines) + { + if (line.Length == 0) + { + insertNewLine = false; + Browser.InvokeScript("append_nl"); + } + else + { + if (insertNewLine == true) + { + Browser.InvokeScript("append_nl"); + } + if (level == 0) + { + Browser.InvokeScript("append_trace", line, "debug"); + } + else if (level == 1) + { + Browser.InvokeScript("append_trace", line, "message"); + } + else if (level == 2) + { + Browser.InvokeScript("append_trace", line, "warning"); + } + else if (level == 3) + { + Browser.InvokeScript("append_trace", line, "error"); + } + else + { + Browser.InvokeScript("append_text", line); + } + insertNewLine = true; + } + } + }); + } + } + + public class UnitTestSuite : OutputTraceListener + { + public UnitTestSuite(string SuiteName, string CaseName, bool Verbose, OutputDisplayDelegate OutputDisplay) + { + this.SuiteName = SuiteName; + this.CaseName = CaseName; + this.Verbose = Verbose; + this.Running = false; + this.OutputDisplay = OutputDisplay; + } + + async public void run() + { + Running = true; + var tup = new Tuple(SuiteName, CaseName, Verbose); + var t = Task.Factory.StartNew((object parameters) => + { + var tester = (Application.Current as App).tester; + tester.setOutputTraceListener(this); + var p = parameters as Tuple; + tester.run(p.Item1, p.Item2, p.Item3); + }, tup); + await t; + Running = false; + } + + public void outputTrace(int level, String msg) + { + if (OutputDisplay != null) + { + OutputDisplay(level, msg); + } + System.Diagnostics.Debug.WriteLine(msg); + } + + public bool running { + get { return Running; } + protected set { Running = value; } + } + + private string SuiteName; + private string CaseName; + private bool Verbose; + private bool Running; + private OutputDisplayDelegate OutputDisplay; + } +} \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/log.html b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/log.html new file mode 100644 index 000000000..4fea1c8bb --- /dev/null +++ b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/log.html @@ -0,0 +1,34 @@ + + + + + + +

+ + diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj new file mode 100644 index 000000000..3b8e9bfc0 --- /dev/null +++ b/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj @@ -0,0 +1,166 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {5e94a00b-b14a-4e42-8284-8cb0ef099534} + linphone_tester_native + en-US + 11.0 + true + + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + true + v110_wp80 + true + + + DynamicLibrary + false + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + false + + + + _USRDLL;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + true + + + + + _USRDLL;NDEBUG;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + false + + + + + Level4 + WIN32;_DEBUG;_WINDOWS;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;HAVE_CU_GET_SUITE;IN_LINPHONE;%(PreprocessorDefinitions) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\windows\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories) + Default + NotUsing + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + false + Async + + + Console + false + ole32.lib;%(IgnoreSpecificDefaultLibraries) + true + WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;ws2_32.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration) + + + + + _USRDLL;NDEBUG;%(PreprocessorDefinitions) + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\windows\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories) + + + Console + false + false + false + + + + + true + false + + + + + + + + + + + + true + + + + + + + + + {902daf1d-ebf1-4d03-b598-143500a50ab4} + + + {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + + {ffc7b532-0502-4d88-ac98-9e89071cbc97} + + + {08dd0d38-d9b5-4626-b60d-b4d76b571142} + + + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.cpp b/build/vsx/LibLinphoneTester/linphone-tester-native.cpp new file mode 100644 index 000000000..941b50916 --- /dev/null +++ b/build/vsx/LibLinphoneTester/linphone-tester-native.cpp @@ -0,0 +1,125 @@ +#include + +#include "linphone-tester-native.h" +#include "ortp/logging.h" +#include "cunit/Util.h" + + +using namespace linphone_tester_native; +using namespace Platform; + +#define MAX_TRACE_SIZE 512 +#define MAX_SUITE_NAME_SIZE 128 + +static OutputTraceListener^ sTraceListener; + +static void nativeOutputTraceHandler(OutputTraceLevel lev, const char *fmt, va_list args) +{ + if (sTraceListener) { + wchar_t wstr[MAX_TRACE_SIZE]; + std::string str; + str.resize(MAX_TRACE_SIZE); + vsnprintf((char *)str.c_str(), MAX_TRACE_SIZE, fmt, args); + mbstowcs(wstr, str.c_str(), sizeof(wstr)); + String^ msg = ref new String(wstr); + sTraceListener->outputTrace(lev, msg); + } +} + +static void LinphoneNativeGenericOutputTraceHandler(OrtpLogLevel lev, const char *fmt, va_list args) +{ + OutputTraceLevel level = Message; + char fmt2[MAX_TRACE_SIZE]; + snprintf(fmt2, MAX_TRACE_SIZE, "%s\n", fmt); + if (lev == ORTP_DEBUG) level = Debug; + else if (lev == ORTP_MESSAGE) level = Message; + else if (lev == ORTP_TRACE) level = Message; + else if (lev == ORTP_WARNING) level = Warning; + else if (lev == ORTP_ERROR) level = Error; + else if (lev == ORTP_FATAL) level = Error; + nativeOutputTraceHandler(level, fmt2, args); +} + +static void LinphoneNativeOutputTraceHandler(OrtpLogLevel lev, const char *fmt, va_list args) +{ + if (lev >= ORTP_WARNING) { + LinphoneNativeGenericOutputTraceHandler(lev, fmt, args); + } +} + +static void LinphoneNativeVerboseOutputTraceHandler(OrtpLogLevel lev, const char *fmt, va_list args) +{ + LinphoneNativeGenericOutputTraceHandler(lev, fmt, args); +} + +static void CUnitNativeOutputTraceHandler(int lev, const char *fmt, va_list args) +{ + nativeOutputTraceHandler(Raw, fmt, args); +} + +LinphoneTesterNative::LinphoneTesterNative() +{ + liblinphone_tester_init(); +} + +LinphoneTesterNative::~LinphoneTesterNative() +{ + liblinphone_tester_uninit(); +} + +void LinphoneTesterNative::setOutputTraceListener(OutputTraceListener^ traceListener) +{ + sTraceListener = traceListener; +} + +void LinphoneTesterNative::run(Platform::String^ suiteName, Platform::String^ caseName, Platform::Boolean verbose) +{ + std::wstring all(L"ALL"); + std::wstring wssuitename = suiteName->Data(); + std::wstring wscasename = caseName->Data(); + char csuitename[MAX_SUITE_NAME_SIZE] = { 0 }; + char ccasename[MAX_SUITE_NAME_SIZE] = { 0 }; + wcstombs(csuitename, wssuitename.c_str(), sizeof(csuitename)); + wcstombs(ccasename, wscasename.c_str(), sizeof(ccasename)); + + if (verbose) { + linphone_core_enable_logs_with_cb(LinphoneNativeVerboseOutputTraceHandler); + } else { + linphone_core_enable_logs_with_cb(LinphoneNativeOutputTraceHandler); + } + CU_set_trace_handler(CUnitNativeOutputTraceHandler); + + liblinphone_tester_run_tests(wssuitename == all ? 0 : csuitename, wscasename == all ? 0 : ccasename); +} + +unsigned int LinphoneTesterNative::nbTestSuites() +{ + return liblinphone_tester_nb_test_suites(); +} + +unsigned int LinphoneTesterNative::nbTests(Platform::String^ suiteName) +{ + std::wstring suitename = suiteName->Data(); + char cname[MAX_SUITE_NAME_SIZE] = { 0 }; + wcstombs(cname, suitename.c_str(), sizeof(cname)); + return liblinphone_tester_nb_tests(cname); +} + +Platform::String^ LinphoneTesterNative::testSuiteName(int index) +{ + const char *cname = liblinphone_tester_test_suite_name(index); + wchar_t wcname[MAX_SUITE_NAME_SIZE]; + mbstowcs(wcname, cname, sizeof(wcname)); + return ref new String(wcname); +} + +Platform::String^ LinphoneTesterNative::testName(Platform::String^ suiteName, int testIndex) +{ + std::wstring suitename = suiteName->Data(); + char csuitename[MAX_SUITE_NAME_SIZE] = { 0 }; + wcstombs(csuitename, suitename.c_str(), sizeof(csuitename)); + const char *cname = liblinphone_tester_test_name(csuitename, testIndex); + wchar_t wcname[MAX_SUITE_NAME_SIZE]; + mbstowcs(wcname, cname, sizeof(wcname)); + return ref new String(wcname); +} diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.h b/build/vsx/LibLinphoneTester/linphone-tester-native.h new file mode 100644 index 000000000..b46b57af0 --- /dev/null +++ b/build/vsx/LibLinphoneTester/linphone-tester-native.h @@ -0,0 +1,33 @@ +#pragma once + +#include "liblinphone_tester.h" + +namespace linphone_tester_native +{ + enum OutputTraceLevel { + Debug, + Message, + Warning, + Error, + Raw + }; + + public interface class OutputTraceListener + { + public: + void outputTrace(int level, Platform::String^ msg); + }; + + public ref class LinphoneTesterNative sealed + { + public: + LinphoneTesterNative(); + virtual ~LinphoneTesterNative(); + void setOutputTraceListener(OutputTraceListener^ traceListener); + unsigned int nbTestSuites(); + unsigned int nbTests(Platform::String^ suiteName); + Platform::String^ testSuiteName(int index); + Platform::String^ testName(Platform::String^ suiteName, int testIndex); + void run(Platform::String^ suiteName, Platform::String^ caseName, Platform::Boolean verbose); + }; +} \ No newline at end of file diff --git a/build/vsx/libxml2/libxml2.sln b/build/vsx/libxml2/libxml2.sln new file mode 100644 index 000000000..62fad2d3f --- /dev/null +++ b/build/vsx/libxml2/libxml2.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Phone +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|Win32 = Debug|Win32 + Release|ARM = Release|ARM + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.ActiveCfg = Debug|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.Build.0 = Debug|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.Build.0 = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.ActiveCfg = Release|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.Build.0 = Release|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.ActiveCfg = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/vsx/libxml2/libxml2/install_headers.bat b/build/vsx/libxml2/libxml2/install_headers.bat new file mode 100644 index 000000000..8e97127d8 --- /dev/null +++ b/build/vsx/libxml2/libxml2/install_headers.bat @@ -0,0 +1,6 @@ +SET curdir=%CD% +SET incdir=..\..\..\..\..\libxml2\include\libxml +SET installdir=%1\libxml + +Xcopy /I /Y %incdir%\*.h %installdir%\ +Xcopy /I /Y xmlversion.h %installdir%\ diff --git a/build/vsx/libxml2/libxml2/libxml2.vcxproj b/build/vsx/libxml2/libxml2/libxml2.vcxproj new file mode 100644 index 000000000..fb873bf4e --- /dev/null +++ b/build/vsx/libxml2/libxml2/libxml2.vcxproj @@ -0,0 +1,249 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} + libxml2 + en-US + 11.0 + + + + DynamicLibrary + true + v110 + false + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ + + + false + + + + Level4 + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) + _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) + LIBXML_MODULES_ENABLED + false + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h + + + Console + false + false + true + $(TargetDir)$(TargetName)_dll.lib + Ws2_32.lib;%(AdditionalDependencies) + + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + Level4 + MaxSpeed + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) + _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) + LIBXML_MODULES_ENABLED + true + true + Default + true + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h + + + Console + false + false + false + $(TargetDir)$(TargetName)_dll.lib + Ws2_32.lib;%(AdditionalDependencies) + + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + Level4 + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) + _WIN32;WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) + LIBXML_MODULES_ENABLED + false + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h + + + Console + false + false + true + $(TargetDir)$(TargetName)_dll.lib + Ws2_32.lib;%(AdditionalDependencies) + + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + Level4 + MaxSpeed + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) + _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) + LIBXML_MODULES_ENABLED + true + true + Default + true + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h + + + Console + false + false + false + $(TargetDir)$(TargetName)_dll.lib + Ws2_32.lib;%(AdditionalDependencies) + + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + true + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/libxml2/libxml2/libxml2_port.h b/build/vsx/libxml2/libxml2/libxml2_port.h new file mode 100644 index 000000000..bde826374 --- /dev/null +++ b/build/vsx/libxml2/libxml2/libxml2_port.h @@ -0,0 +1,19 @@ + +#ifndef LIBXML2_PORT_H +#define LIBXML2_PORT_H + +#define CreateMutex(a, b, c) CreateMutexExW(a, c, ((b) ? CREATE_MUTEX_INITIAL_OWNER : 0), 0) + +#define GetVersionEx(osvi) (((osvi)->dwPlatformId = 0) != 0) + +#define InitializeCriticalSection(cs) InitializeCriticalSectionEx(cs, 0, 0) + +#define WaitForSingleObject(hHandle, dwMilliseconds) WaitForSingleObjectEx(hHandle, dwMilliseconds, 0) + +#define Sleep(ms) { \ + HANDLE sleepEvent = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); \ + if (!sleepEvent) return; \ + WaitForSingleObjectEx(sleepEvent, ms, FALSE); \ +} + +#endif /* LIBXML2_PORT_H */ diff --git a/build/vsx/libxml2/libxml2/xmlversion.h b/build/vsx/libxml2/libxml2/xmlversion.h new file mode 100644 index 000000000..40c192eba --- /dev/null +++ b/build/vsx/libxml2/libxml2/xmlversion.h @@ -0,0 +1,476 @@ +/* + * Summary: compile-time version informations + * Description: compile-time version informations for the XML library + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_VERSION_H__ +#define __XML_VERSION_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * use those to be sure nothing nasty will happen if + * your library and includes mismatch + */ +#ifndef LIBXML2_COMPILING_MSCCDEF +XMLPUBFUN void XMLCALL xmlCheckVersion(int version); +#endif /* LIBXML2_COMPILING_MSCCDEF */ + +/** + * LIBXML_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXML_DOTTED_VERSION "2.8.0" + +/** + * LIBXML_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBXML_VERSION 20800 + +/** + * LIBXML_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBXML_VERSION_STRING "20800" + +/** + * LIBXML_VERSION_EXTRA: + * + * extra version information, used to show a CVS compilation + */ +#define LIBXML_VERSION_EXTRA "" + +/** + * LIBXML_TEST_VERSION: + * + * Macro to check that the libxml version in use is compatible with + * the version the software has been compiled against + */ +#define LIBXML_TEST_VERSION xmlCheckVersion(20800); + +#ifndef VMS +#if 0 +/** + * WITH_TRIO: + * + * defined if the trio support need to be configured in + */ +#define WITH_TRIO +#else +/** + * WITHOUT_TRIO: + * + * defined if the trio support should not be configured in + */ +#define WITHOUT_TRIO +#endif +#else /* VMS */ +/** + * WITH_TRIO: + * + * defined if the trio support need to be configured in + */ +#define WITH_TRIO 1 +#endif /* VMS */ + +/** + * LIBXML_THREAD_ENABLED: + * + * Whether the thread support is configured in + */ +#if 1 +#if defined(_REENTRANT) || defined(__MT__) || \ + (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0 >= 199506L)) +#define LIBXML_THREAD_ENABLED +#endif +#endif + +/** + * LIBXML_TREE_ENABLED: + * + * Whether the DOM like tree manipulation API support is configured in + */ +#if 1 +#define LIBXML_TREE_ENABLED +#endif + +/** + * LIBXML_OUTPUT_ENABLED: + * + * Whether the serialization/saving support is configured in + */ +#if 1 +#define LIBXML_OUTPUT_ENABLED +#endif + +/** + * LIBXML_PUSH_ENABLED: + * + * Whether the push parsing interfaces are configured in + */ +#if 1 +#define LIBXML_PUSH_ENABLED +#endif + +/** + * LIBXML_READER_ENABLED: + * + * Whether the xmlReader parsing interface is configured in + */ +#if 1 +#define LIBXML_READER_ENABLED +#endif + +/** + * LIBXML_PATTERN_ENABLED: + * + * Whether the xmlPattern node selection interface is configured in + */ +#if 1 +#define LIBXML_PATTERN_ENABLED +#endif + +/** + * LIBXML_WRITER_ENABLED: + * + * Whether the xmlWriter saving interface is configured in + */ +#if 1 +#define LIBXML_WRITER_ENABLED +#endif + +/** + * LIBXML_SAX1_ENABLED: + * + * Whether the older SAX1 interface is configured in + */ +#if 1 +#define LIBXML_SAX1_ENABLED +#endif + +/** + * LIBXML_FTP_ENABLED: + * + * Whether the FTP support is configured in + */ +#if 1 +#define LIBXML_FTP_ENABLED +#endif + +/** + * LIBXML_HTTP_ENABLED: + * + * Whether the HTTP support is configured in + */ +#if 1 +#define LIBXML_HTTP_ENABLED +#endif + +/** + * LIBXML_VALID_ENABLED: + * + * Whether the DTD validation support is configured in + */ +#if 1 +#define LIBXML_VALID_ENABLED +#endif + +/** + * LIBXML_HTML_ENABLED: + * + * Whether the HTML support is configured in + */ +#if 1 +#define LIBXML_HTML_ENABLED +#endif + +/** + * LIBXML_LEGACY_ENABLED: + * + * Whether the deprecated APIs are compiled in for compatibility + */ +#if 1 +#define LIBXML_LEGACY_ENABLED +#endif + +/** + * LIBXML_C14N_ENABLED: + * + * Whether the Canonicalization support is configured in + */ +#if 1 +#define LIBXML_C14N_ENABLED +#endif + +/** + * LIBXML_CATALOG_ENABLED: + * + * Whether the Catalog support is configured in + */ +#if 0 +#define LIBXML_CATALOG_ENABLED +#endif + +/** + * LIBXML_DOCB_ENABLED: + * + * Whether the SGML Docbook support is configured in + */ +#if 1 +#define LIBXML_DOCB_ENABLED +#endif + +/** + * LIBXML_XPATH_ENABLED: + * + * Whether XPath is configured in + */ +#if 1 +#define LIBXML_XPATH_ENABLED +#endif + +/** + * LIBXML_XPTR_ENABLED: + * + * Whether XPointer is configured in + */ +#if 1 +#define LIBXML_XPTR_ENABLED +#endif + +/** + * LIBXML_XINCLUDE_ENABLED: + * + * Whether XInclude is configured in + */ +#if 1 +#define LIBXML_XINCLUDE_ENABLED +#endif + +/** + * LIBXML_ICONV_ENABLED: + * + * Whether iconv support is available + */ +#if 0 +#define LIBXML_ICONV_ENABLED +#endif + +/** + * LIBXML_ICU_ENABLED: + * + * Whether icu support is available + */ +#if 0 +#define LIBXML_ICU_ENABLED +#endif + +/** + * LIBXML_ISO8859X_ENABLED: + * + * Whether ISO-8859-* support is made available in case iconv is not + */ +#if 0 +#define LIBXML_ISO8859X_ENABLED +#endif + +/** + * LIBXML_DEBUG_ENABLED: + * + * Whether Debugging module is configured in + */ +#if 1 +#define LIBXML_DEBUG_ENABLED +#endif + +/** + * DEBUG_MEMORY_LOCATION: + * + * Whether the memory debugging is configured in + */ +#if 0 +#define DEBUG_MEMORY_LOCATION +#endif + +/** + * LIBXML_DEBUG_RUNTIME: + * + * Whether the runtime debugging is configured in + */ +#if 0 +#define LIBXML_DEBUG_RUNTIME +#endif + +/** + * LIBXML_UNICODE_ENABLED: + * + * Whether the Unicode related interfaces are compiled in + */ +#if 1 +#define LIBXML_UNICODE_ENABLED +#endif + +/** + * LIBXML_REGEXP_ENABLED: + * + * Whether the regular expressions interfaces are compiled in + */ +#if 1 +#define LIBXML_REGEXP_ENABLED +#endif + +/** + * LIBXML_AUTOMATA_ENABLED: + * + * Whether the automata interfaces are compiled in + */ +#if 1 +#define LIBXML_AUTOMATA_ENABLED +#endif + +/** + * LIBXML_EXPR_ENABLED: + * + * Whether the formal expressions interfaces are compiled in + */ +#if 1 +#define LIBXML_EXPR_ENABLED +#endif + +/** + * LIBXML_SCHEMAS_ENABLED: + * + * Whether the Schemas validation interfaces are compiled in + */ +#if 1 +#define LIBXML_SCHEMAS_ENABLED +#endif + +/** + * LIBXML_SCHEMATRON_ENABLED: + * + * Whether the Schematron validation interfaces are compiled in + */ +#if 1 +#define LIBXML_SCHEMATRON_ENABLED +#endif + +/** + * LIBXML_MODULES_ENABLED: + * + * Whether the module interfaces are compiled in + */ +#if 0 +#define LIBXML_MODULES_ENABLED +/** + * LIBXML_MODULE_EXTENSION: + * + * the string suffix used by dynamic modules (usually shared libraries) + */ +#define LIBXML_MODULE_EXTENSION ".dll" +#endif + +/** + * LIBXML_ZLIB_ENABLED: + * + * Whether the Zlib support is compiled in + */ +#if 0 +#define LIBXML_ZLIB_ENABLED +#endif + +/** + * LIBXML_LZMA_ENABLED: + * + * Whether the Lzma support is compiled in + */ +#if 0 +#define LIBXML_LZMA_ENABLED +#endif + +#ifdef __GNUC__ +#ifdef HAVE_ANSIDECL_H +#include +#endif + +/** + * ATTRIBUTE_UNUSED: + * + * Macro used to signal to GCC unused function parameters + */ + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#endif + +/** + * LIBXML_ATTR_ALLOC_SIZE: + * + * Macro used to indicate to GCC this is an allocator function + */ + +#ifndef LIBXML_ATTR_ALLOC_SIZE +# if ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))) +# define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) +# else +# define LIBXML_ATTR_ALLOC_SIZE(x) +# endif +#else +# define LIBXML_ATTR_ALLOC_SIZE(x) +#endif + +/** + * LIBXML_ATTR_FORMAT: + * + * Macro used to indicate to GCC the parameter are printf like + */ + +#ifndef LIBXML_ATTR_FORMAT +# if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3))) +# define LIBXML_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args))) +# else +# define LIBXML_ATTR_FORMAT(fmt,args) +# endif +#else +# define LIBXML_ATTR_FORMAT(fmt,args) +#endif + +#else /* ! __GNUC__ */ +/** + * ATTRIBUTE_UNUSED: + * + * Macro used to signal to GCC unused function parameters + */ +#define ATTRIBUTE_UNUSED +/** + * LIBXML_ATTR_ALLOC_SIZE: + * + * Macro used to indicate to GCC this is an allocator function + */ +#define LIBXML_ATTR_ALLOC_SIZE(x) +/** + * LIBXML_ATTR_FORMAT: + * + * Macro used to indicate to GCC the parameter are printf like + */ +#define LIBXML_ATTR_FORMAT(fmt,args) +#endif /* __GNUC__ */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif + + diff --git a/configure.ac b/configure.ac index d74897614..dc473517e 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([linphone],[3.6.1],[linphone-developers@nongnu.org]) +AC_INIT([linphone],[3.6.99],[linphone-developers@nongnu.org]) AC_CANONICAL_SYSTEM AC_CONFIG_SRCDIR([coreapi/linphonecore.c]) @@ -23,6 +23,7 @@ LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to LIBLINPHONE_SO_VERSION=$LIBLINPHONE_SO_CURRENT:$LIBLINPHONE_SO_REVISION:$LIBLINPHONE_SO_AGE +AC_SUBST(LIBLINPHONE_SO_CURRENT, $LIBLINPHONE_SO_CURRENT) AC_SUBST(LIBLINPHONE_SO_VERSION, $LIBLINPHONE_SO_VERSION) AC_SUBST(LINPHONE_VERSION) @@ -35,9 +36,13 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],) AC_SUBST([docdir], [${datadir}/doc]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) +dnl don't put anythingelse before AC_PROG_CC unless checking if macro still work for clang +AC_PROG_CXX(["xcrun clang++" g++]) +AC_PROG_CC(["xcrun clang" gcc]) + +gl_LD_OUTPUT_DEF + AC_ISC_POSIX -AC_PROG_CC -AC_PROG_CXX AC_C_INLINE AC_HEADER_STDC AM_PROG_CC_C_O @@ -59,10 +64,10 @@ case $target in GUI_FLAGS="-mwindows" CONSOLE_FLAGS="-mconsole" mingw_found=yes + AC_CHECK_TOOL(WINDRES, windres) ;; armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin) - CFLAGS="$CFLAGS -DTARGET_OS_IPHONE " - build_tests=no + CFLAGS="$CFLAGS -DTARGET_OS_IPHONE=1 " ios_found=yes ;; x86_64-apple-darwin*|i686-apple-darwin*) @@ -74,15 +79,24 @@ case $target in esac + + + AC_SUBST(ACLOCAL_MACOS_FLAGS) AC_SUBST(CONSOLE_FLAGS) AC_SUBST(GUI_FLAGS) +case "$build_os" in + *darwin*) + HTTPS_CA_DIR=`openssl version -d | sed "s/OPENSSLDIR: \"\(.*\)\"/\1/"` + ;; +esac + +AC_SUBST(HTTPS_CA_DIR) + dnl localization tools IT_PROG_INTLTOOL([0.40], [no-xml]) -AM_CONDITIONAL(BUILD_TESTS,test x$build_tests != xno) - dnl Initialize libtool LT_INIT([win32-dll shared disable-static]) @@ -127,13 +141,15 @@ if test "$mingw_found" != "yes" ; then CPPFLAGS=$CPPFLAGS_save LIBS="$LIBS $LIBINTL" else - AC_DEFINE(ENABLE_NLS,1,[Tells whether localisation is possible]) - AC_DEFINE(HAVE_GETTEXT,1,[Tells wheter localisation is possible]) - LIBS="$LIBS -lintl" + if test "$USE_NLS" = "yes" ; then + AC_DEFINE(ENABLE_NLS,1,[Tells whether localisation is possible]) + AC_DEFINE(HAVE_GETTEXT,1,[Tells wheter localisation is possible]) + LIBS="$LIBS -lintl" + fi fi GETTEXT_PACKAGE=linphone -AC_SUBST(GETTEXT_PACKAGE) +AC_SUBST([GETTEXT_PACKAGE]) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[The name of the gettext package name]) dnl AC_CHECK_LIB(intl,libintl_gettext) @@ -203,15 +219,10 @@ if test "$build_upnp" != "false" ; then AC_DEFINE(BUILD_UPNP, 1, [Define if upnp enabled]) fi -dnl check libxml2 (needed for tools) -if test "$build_tools" != "false" ; then - PKG_CHECK_MODULES(LIBXML2, [libxml-2.0],[], - [if test "$build_tools" = "true" ; then - AC_MSG_ERROR([Could not found libxml2, tools cannot be compiled.]) - else - build_tools=false - fi] - ) +dnl check libxml2 +PKG_CHECK_MODULES(LIBXML2, [libxml-2.0],[libxml2_found=yes],foo=bar) +if test "$libxml2_found" != "yes" ; then + AC_MSG_ERROR([libxml2 not found. Install it and try again (the package is usually named libxml2-dev in the Linux distributions)]) fi AM_CONDITIONAL(BUILD_TOOLS, test x$build_tools != xfalse) @@ -356,6 +367,25 @@ AC_ARG_ENABLE(debug, esac], [debug_enabled=no] ) +AS_CASE([$debug_enabled], + [yes],[ + CFLAGS="$CFLAGS -g -DDEBUG" + CXXFLAGS="$CXXFLAGS -g -DDEBUG" + OBJCFLAGS="$OBJCFLAGS -g -DDEBUG" + ], + [no], + [ + case "$CFLAGS" in + *-O*) + ;; + *) + CFLAGS="$CFLAGS -O2 -g" + CXXFLAGS="$CXXFLAGS -O2 -g" + OBJCFLAGS="$OBJCFLAGS -O2 -g" + ;; + esac + ], + [AC_MSG_ERROR([Bad value ($debug_enabled) for --enable-debug. Valid values are yes or no.])]) dnl enable truespeech codec support AC_ARG_ENABLE(truespeech, @@ -387,13 +417,6 @@ AC_ARG_ENABLE(nonstandard-gsm, [exotic_gsm=no] ) - -dnl support for RSVP (by Vincent Maury) -AC_ARG_ENABLE(rsvp, - [AS_HELP_STRING([--enable-rsvp], [Enable support for QoS reservations.])], - AC_DEFINE(VINCENT_MAURY_RSVP,1,[Tell whether RSVP support should be compiled.]) -) - if test "x${prefix}" = "xNONE"; then package_prefix=${ac_default_prefix} else @@ -424,26 +447,6 @@ AC_DEFINE_UNQUOTED(PACKAGE_SOUND_DIR, "${package_prefix}/${DATADIRNAME}/sounds/l dnl check if we have the getifaddrs() sytem call AC_CHECK_FUNCS(getifaddrs) -dnl check for osip2 -LP_CHECK_OSIP2 - -dnl conditionnal build for ssl -AC_ARG_ENABLE(ssl, - [AS_HELP_STRING([--enable-ssl], [Turn on ssl support compiling. Required for sip tls. (default=false)])], - [case "${enableval}" in - yes) build_ssl=true ;; - no) build_ssl=false ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-ssl) ;; - esac], - [build_ssl=false] -) - -if test "$build_ssl" = "true"; then - PKG_CHECK_MODULES(OPENSSL, libssl >= 0.9.8) -fi -dnl setup flags for exosip library -LP_SETUP_EXOSIP - if test "$console_ui" = "true" ; then dnl check gnu readline LP_CHECK_READLINE @@ -604,7 +607,15 @@ AC_ARG_ENABLE(strict, [strictness=yes] ) -STRICT_OPTIONS="-Wall " +STRICT_OPTIONS="-Wall" + +#for clang + +case $CC in + *clang*) + STRICT_OPTIONS="$STRICT_OPTIONS -Qunused-arguments" + ;; +esac if test "$strictness" = "yes" ; then STRICT_OPTIONS="$STRICT_OPTIONS -Werror" @@ -686,6 +697,15 @@ if test x$enable_msg_storage != xfalse; then fi + +PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.2.0]) + +SIPSTACK_CFLAGS="$BELLESIP_CFLAGS" +SIPSTACK_LIBS="$BELLESIP_LIBS" + + +AC_SUBST(SIPSTACK_CFLAGS) +AC_SUBST(SIPSTACK_LIBS) dnl check for db2html (docbook) to generate html user manual AC_CHECK_PROG(have_sgmltools, sgmltools, yes, no) @@ -693,11 +713,8 @@ 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" +LINPHONE_LIBS="-L${libdir} -llinphone -llpc2xml -lxml2lpc" -if test x$mingw_found = xyes ; then - LINPHONE_LIBS="$LINPHONE_LIBS $OSIP_LIBS" -fi AC_SUBST(LINPHONE_CFLAGS) AC_SUBST(LINPHONE_LIBS) @@ -740,18 +757,62 @@ AC_SUBST(ORTP_LIBS) AC_SUBST([ORTP_VERSION]) AC_SUBST([ORTP_DIR]) -AC_ARG_ENABLE(tests_enabled, +AC_ARG_ENABLE(tutorials, + [AS_HELP_STRING([--disable-tutorials], [Disable compilation of tutorials])], + [case "${enableval}" in + yes) tutorials_enabled=true ;; + no) tutorials_enabled=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-tutorials) ;; + esac], + [tutorials_enabled=yes] +) +AM_CONDITIONAL(ENABLE_TUTORIALS, test x$tutorials_enabled = xyes) + +AC_ARG_ENABLE(tests, [AS_HELP_STRING([--disable-tests], [Disable compilation of tests])], [case "${enableval}" in yes) tests_enabled=true ;; no) tests_enabled=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-tests) ;; esac], - [tests_enabled=false] + [tests_enabled=yes] ) AM_CONDITIONAL(ENABLE_TESTS, test x$tests_enabled = xyes) +PKG_CHECK_MODULES(CUNIT, cunit, [found_cunit=yes],[found_cunit=no]) +if test "$found_cunit" = "no" ; then + AC_CHECK_HEADERS(CUnit/CUnit.h, + [ + AC_CHECK_LIB(cunit,CU_add_suite,[ + found_cunit=yes + CUNIT_LIBS+=" -lcunit" + ]) + + ]) +fi + +case "$target_os" in + *darwin*) + #hack for macport + CUNIT_LIBS+=" -lncurses" + ;; +esac +AM_CONDITIONAL([BUILD_CUNIT_TESTS], [test x$found_cunit = xyes && test x$tests_enabled != xfalse]) +if test "$found_cunit" = "no" ; then + AC_MSG_WARN([Could not find cunit framework, tests are not compiled.]) +else + AC_CHECK_LIB(cunit,CU_curses_run_tests,[ + AC_DEFINE(HAVE_CU_CURSES,1,[defined when CU_curses_run_tests is available]) + ],[foo=bar],[$CUNIT_LIBS]) +fi + +case "$target_os" in + *linux*) + # Eliminate -lstdc++ addition to postdeps for cross compiles. + postdeps_CXX=`echo " $postdeps_CXX " | sed 's, -lstdc++ ,,g'` + ;; +esac dnl ################################################## dnl # Check for doxygen @@ -769,9 +830,11 @@ AC_CONFIG_FILES([ m4/Makefile po/Makefile.in pixmaps/Makefile + include/Makefile coreapi/Makefile coreapi/help/Makefile coreapi/help/Doxyfile + tester/Makefile gtk/Makefile console/Makefile daemon/Makefile @@ -804,7 +867,8 @@ printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp printf "* %-30s %s\n" "uPnP support" $build_upnp if test "$enable_tunnel" = "true" ; then - printf "* Tunnel support\t\ttrue\n" + printf "* %-30s %s\n" "Tunnel support" "true" fi + echo "Now type 'make' to compile, and then 'make install' as root to install it." diff --git a/console/Makefile.am b/console/Makefile.am index 976cbeafa..84e0c94cd 100644 --- a/console/Makefile.am +++ b/console/Makefile.am @@ -3,19 +3,17 @@ AM_CPPFLAGS=\ -I$(top_srcdir) \ -I$(top_srcdir)/coreapi \ - -I$(top_srcdir)/exosip + -I$(top_srcdir)/include COMMON_CFLAGS=\ -DIN_LINPHONE \ - -DENABLE_TRACE \ -D_ORTP_SOURCE \ $(STRICT_OPTIONS) \ + $(ORTP_CFLAGS) \ + $(MEDIASTREAMER_CFLAGS) \ $(VIDEO_CFLAGS) \ $(READLINE_CFLAGS) \ - $(OSIP_CFLAGS) \ - $(ORTP_CFLAGS) \ - $(SQLITE3_CFLAGS) \ - $(MEDIASTREAMER_CFLAGS) + $(SQLITE3_CFLAGS) if BUILD_CONSOLE diff --git a/console/commands.c b/console/commands.c index 67b2446f4..ba2f1dc3c 100644 --- a/console/commands.c +++ b/console/commands.c @@ -1022,7 +1022,7 @@ lpc_cmd_friend(LinphoneCore *lc, char *args) linphonec_friend_add(lc, name, addr); #else LinphoneFriend *new_friend; - new_friend = linphone_friend_new_with_addr(args); + new_friend = linphone_friend_new_with_address(args); linphone_core_add_friend(lc, new_friend); #endif return 1; @@ -1082,6 +1082,7 @@ lpc_cmd_proxy(LinphoneCore *lc, char *args) } else if (strcmp(arg1,"remove")==0) { + if (arg2==NULL) return 0; linphonec_proxy_remove(lc,atoi(arg2)); } else if (strcmp(arg1,"use")==0) @@ -1109,16 +1110,16 @@ lpc_cmd_proxy(LinphoneCore *lc, char *args) { if (strstr(arg2,"default")) { - proxynum=linphone_core_get_default_proxy(lc, NULL); - if ( proxynum < 0 ) { - linphonec_out("No default proxy defined\n"); - return 1; - } - linphonec_proxy_show(lc,proxynum); + proxynum=linphone_core_get_default_proxy(lc, NULL); + if ( proxynum < 0 ) { + linphonec_out("No default proxy defined\n"); + return 1; + } + linphonec_proxy_show(lc,proxynum); } else { - linphonec_proxy_show(lc, atoi(arg2)); + linphonec_proxy_show(lc, atoi(arg2)); } } else return 0; /* syntax error */ @@ -1615,7 +1616,7 @@ linphonec_proxy_add(LinphoneCore *lc) continue; } - linphone_proxy_config_expires(cfg, expires); + linphone_proxy_config_set_expires(cfg, expires); linphonec_out("Expiration: %d seconds\n", linphone_proxy_config_get_expires (cfg)); free(input); @@ -1852,7 +1853,7 @@ linphonec_friend_add(LinphoneCore *lc, const char *name, const char *addr) char url[PATH_MAX]; snprintf(url, PATH_MAX, "%s <%s>", name, addr); - newFriend = linphone_friend_new_with_addr(url); + newFriend = linphone_friend_new_with_address(url); linphone_core_add_friend(lc, newFriend); return 0; } @@ -1929,9 +1930,7 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){ LinphoneAddress *from; LinphoneAuthInfo *info; if ((from=linphone_address_new(identity))!=NULL){ - char realm[128]; - snprintf(realm,sizeof(realm)-1,"\"%s\"",linphone_address_get_domain(from)); - info=linphone_auth_info_new(linphone_address_get_username(from),NULL,passwd,NULL,NULL); + info=linphone_auth_info_new(NULL,NULL,passwd,NULL,NULL,linphone_address_get_username(from)); linphone_core_add_auth_info(lc,info); linphone_address_destroy(from); linphone_auth_info_destroy(info); @@ -1942,7 +1941,7 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){ cfg=(LinphoneProxyConfig*)elem->data; linphone_proxy_config_edit(cfg); } - else cfg=linphone_proxy_config_new(); + else cfg=linphone_core_create_proxy_config(lc); linphone_proxy_config_set_identity(cfg,identity); linphone_proxy_config_set_server_addr(cfg,proxy); linphone_proxy_config_enable_register(cfg,TRUE); @@ -2030,7 +2029,7 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args) if (linphone_call_get_dir(call)==LinphoneCallOutgoing){ linphonec_out("Call out, hook=%s duration=%i, muted=%s rtp-xmit-muted=%s\n", linphonec_get_callee(), linphone_core_get_current_call_duration(lc), - linphone_core_is_mic_muted (lc) ? "yes" : "no", + linphone_core_mic_enabled(lc) ? "no" : "yes", linphone_core_is_rtp_muted(lc) ? "yes" : "no"); }else{ linphonec_out("hook=answered duration=%i %s\n" , @@ -2110,7 +2109,13 @@ static int lpc_cmd_speak(LinphoneCore *lc, char *args){ memset(voice,0,sizeof(voice)); sscanf(args,"%63s",voice); sentence=args+strlen(voice); + +#ifdef __APPLE__ + wavfile=mktemp("/tmp/linphonec-espeak-XXXXXX"); +#else wavfile=tempnam("/tmp/","linphonec-espeak-"); +#endif + snprintf(cl,sizeof(cl),"espeak -v %s -s 100 -w %s --stdin",voice,wavfile); file=popen(cl,"w"); if (file==NULL){ diff --git a/console/linphonec.c b/console/linphonec.c index 60c3c2af1..4385dbb09 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -117,13 +117,12 @@ static char **linephonec_readline_completion(const char *text, #endif /* These are callback for linphone core */ -static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, - const char *username); +static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username, const char *domain); static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to); static void linphonec_display_something (LinphoneCore * lc, const char *something); static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url); static void linphonec_display_warning (LinphoneCore * lc, const char *something); -static void linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event); +static void linphonec_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState new_call_state); static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid); static void linphonec_new_unknown_subscriber(LinphoneCore *lc, @@ -256,7 +255,7 @@ linphonec_display_url (LinphoneCore * lc, const char *something, const char *url * Linphone core callback */ static void -linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username) +linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { /* no prompt possible when using pipes or tcp mode*/ if (unix_socket){ @@ -272,7 +271,7 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern return; } - pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm); + pending_auth=linphone_auth_info_new(username,NULL,NULL,NULL,realm,domain); auth_stack.elem[auth_stack.nitems++]=pending_auth; } } @@ -281,13 +280,14 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern * Linphone core callback */ static void -linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event) +linphonec_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState new_call_state) { - if(!strcmp(event,"refer")) - { - linphonec_out("The distand endpoint %s of call %li has been transfered, you can safely close the call.\n", - from,(long)linphone_call_get_user_pointer (call)); + char *remote=linphone_call_get_remote_address_as_string(call); + if (new_call_state==LinphoneCallConnected){ + linphonec_out("The distant endpoint %s of call %li has been transfered, you can safely close the call.\n", + remote,(long)linphone_call_get_user_pointer (call)); } + ms_free(remote); } @@ -628,8 +628,8 @@ int main (int argc, char *argv[]) { #endif linphonec_vtable.call_state_changed=linphonec_call_state_changed; - linphonec_vtable.notify_presence_recv = linphonec_notify_presence_received; - linphonec_vtable.new_subscription_request = linphonec_new_unknown_subscriber; + linphonec_vtable.notify_presence_received = linphonec_notify_presence_received; + linphonec_vtable.new_subscription_requested = linphonec_new_unknown_subscriber; linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth; linphonec_vtable.display_status = linphonec_display_status; linphonec_vtable.display_message=linphonec_display_something; @@ -638,7 +638,7 @@ main (int argc, char *argv[]) { linphonec_vtable.text_received=linphonec_text_received; linphonec_vtable.dtmf_received=linphonec_dtmf_received; linphonec_vtable.refer_received=linphonec_display_refer; - linphonec_vtable.notify_recv=linphonec_notify_received; + linphonec_vtable.transfer_state_changed=linphonec_transfer_state_changed; linphonec_vtable.call_encryption_changed=linphonec_call_encryption_changed; if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE); @@ -734,7 +734,8 @@ linphonec_init(int argc, char **argv) */ linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL); linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets); - linphone_core_enable_video(linphonec,vcap_enabled,display_enabled); + linphone_core_enable_video_capture(linphonec, vcap_enabled); + linphone_core_enable_video_display(linphonec, display_enabled); if (display_enabled && window_id != 0) { printf ("Setting window_id: 0x%x\n", window_id); @@ -1074,7 +1075,7 @@ linphonec_initialize_readline() rl_attempted_completion_function = linephonec_readline_completion; /* printf("Readline initialized.\n"); */ - setlinebuf(stdout); + setlinebuf(stdout); return 0; } diff --git a/console/shell.c b/console/shell.c index e61a6e514..bfc758bf8 100644 --- a/console/shell.c +++ b/console/shell.c @@ -25,9 +25,9 @@ #ifdef WIN32 +#include #include #include -#include #include #include #else diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 91fc9bd22..ec0250fa8 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -1,7 +1,8 @@ GITVERSION_FILE=liblinphone_gitversion.h GITVERSION_FILE_TMP=liblinphone_gitversion.h.tmp -GITDESCRIBE=`git describe --always` -GITREVISION=`git rev-parse HEAD` +GITDESCRIBE=`cd $(top_srcdir) && git describe --always` +GIT_TAG=`cd $(top_srcdir) && git describe --abbrev=0` +GITREVISION=`cd $(top_srcdir) && git rev-parse HEAD` ECHO=/bin/echo @@ -16,7 +17,7 @@ CLEANFILES=$(GITVERSION_FILE) ## Process this file with automake to produce Makefile.in linphone_includedir=$(includedir)/linphone -linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonecore_utils.h lpconfig.h sipsetup.h +linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonepresence.h linphonecore_utils.h lpconfig.h sipsetup.h event.h if BUILD_TUNNEL linphone_include_HEADERS+=linphone_tunnel.h @@ -27,10 +28,7 @@ lib_LTLIBRARIES=liblinphone.la liblinphone_la_SOURCES=\ linphonecore.c linphonecore.h private.h\ offeranswer.c offeranswer.h\ - sal.c sal.h \ - sal_eXosip2.c sal_eXosip2.h\ - sal_eXosip2_sdp.c \ - sal_eXosip2_presence.c \ + sal.c \ callbacks.c \ misc.c \ address.c \ @@ -48,12 +46,27 @@ liblinphone_la_SOURCES=\ ec-calibrator.c \ conference.c \ message_storage.c \ + info.c \ + event.c event.h \ $(GITVERSION_FILE) if BUILD_UPNP liblinphone_la_SOURCES+=upnp.c upnp.h endif +liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ + bellesip_sal/sal_impl.c bellesip_sal/sal_impl.h \ + bellesip_sal/sal_op_impl.c \ + bellesip_sal/sal_op_call.c \ + bellesip_sal/sal_op_registration.c \ + bellesip_sal/sal_sdp.c \ + bellesip_sal/sal_op_message.c \ + bellesip_sal/sal_op_presence.c \ + bellesip_sal/sal_op_publish.c \ + bellesip_sal/sal_op_call_transfer.c \ + bellesip_sal/sal_op_info.c \ + bellesip_sal/sal_op_events.c + if BUILD_WIZARD liblinphone_la_SOURCES+=sipwizard.c endif @@ -69,16 +82,32 @@ endif liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined +if HAVE_LD_OUTPUT_DEF +liblinphone_la_LDFLAGS += -Wl,--output-def,liblinphone-$(LIBLINPHONE_SO_CURRENT).def +defexecdir = $(libdir) +defexec_DATA = liblinphone-$(LIBLINPHONE_SO_CURRENT).def +CLEANFILES = $(defexec_DATA) + +liblinphone-$(LIBLINPHONE_SO_CURRENT).def: liblinphone.la + +if BUILD_WIN32 +defexec_DATA += liblinphone-$(LIBLINPHONE_SO_CURRENT).lib +liblinphone-$(LIBLINPHONE_SO_CURRENT).lib: liblinphone-$(LIBLINPHONE_SO_CURRENT).def liblinphone.la + $(DLLTOOL) --dllname liblinphone-$(LIBLINPHONE_SO_CURRENT).dll --input-def liblinphone-$(LIBLINPHONE_SO_CURRENT).def --output-lib $@ liblinphone.la +endif +endif + liblinphone_la_LIBADD= \ - $(EXOSIP_LIBS) \ + $(SIPSTACK_LIBS) \ $(MEDIASTREAMER_LIBS) \ $(ORTP_LIBS) $(OPENSSL_LIBS) \ $(TUNNEL_LIBS) \ $(LIBSOUP_LIBS) \ - $(SQLITE3_LIBS) + $(SQLITE3_LIBS) \ + $(LIBXML2_LIBS) -if BUILD_TESTS +if ENABLE_TESTS noinst_PROGRAMS=test_lsd test_ecc test_numbers test_lsd_SOURCES=test_lsd.c @@ -95,14 +124,13 @@ test_numbers_LDADD=liblinphone.la $(liblinphone_la_LIBADD) endif AM_CPPFLAGS=\ - -I$(top_srcdir) + -I$(top_srcdir) -I$(top_srcdir)/include AM_CFLAGS=\ $(STRICT_OPTIONS) -DIN_LINPHONE \ $(ORTP_CFLAGS) \ $(MEDIASTREAMER_CFLAGS) \ - $(OSIP_CFLAGS) \ - $(EXOSIP_CFLAGS) \ + $(SIPSTACK_CFLAGS) \ $(LIBSOUP_CFLAGS) \ -DENABLE_TRACE \ -DLOG_DOMAIN=\"LinphoneCore\" \ @@ -110,16 +138,23 @@ AM_CFLAGS=\ -DORTP_INET6 \ $(VIDEO_CFLAGS) \ $(TUNNEL_CFLAGS) \ - $(SQLITE3_CFLAGS) + $(SQLITE3_CFLAGS) \ + $(LIBXML2_CFLAGS) if BUILD_WIZARD AM_CFLAGS+= -DBUILD_WIZARD endif +AM_CFLAGS+= -DUSE_BELLESIP + AM_CXXFLAGS=$(AM_CFLAGS) make_gitversion_h: if test "$(GITDESCRIBE)" != "" ; then \ + if test "$(GIT_TAG)" != "$(PACKAGE_VERSION)" ; then \ + echo "*** PACKAGE_VERSION and git tag differ. Please put them identical."; \ + exit 1; \ + fi ; \ $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"" > $(GITVERSION_FILE_TMP) ; \ elif test "$(GITREVISION)" != "" ; then \ $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \ diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index 409f9c42a..efac8fbb0 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -16,8 +16,11 @@ #include "ortp/rtpsession.h" #include "linphonecore.h" #include "linphonecore_utils.h" +#ifndef USE_BELLESIP #include "eXosip2/eXosip_transport_hook.h" +#endif #include "tunnel/udp_mirror.hh" +#include "private.h" #ifdef ANDROID #include @@ -27,6 +30,8 @@ using namespace belledonnecomm; using namespace ::std; +#ifndef USE_BELLESIP + Mutex TunnelManager::sMutex; int TunnelManager::eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata){ @@ -99,6 +104,7 @@ int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, return select(max_fds,s1,s2,s3,tv); } } +#endif void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) { @@ -181,7 +187,9 @@ void TunnelManager::start() { } mTunnelClient->start(); +#ifndef USE_BELLESIP if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060); +#endif } bool TunnelManager::isStarted() { @@ -209,7 +217,9 @@ int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flag TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() ,mCore(lc) +#ifndef USE_BELLESIP ,mSipSocket(NULL) +#endif ,mCallback(NULL) ,mEnabled(false) ,mTunnelClient(NULL) @@ -217,10 +227,12 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() ,mReady(false) ,mHttpProxyPort(0){ +#ifndef USE_BELLESIP mExosipTransport.data=this; mExosipTransport.recvfrom=eXosipRecvfrom; mExosipTransport.sendto=eXosipSendto; mExosipTransport.select=eXosipSelect; +#endif linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this); mTransportFactories.audio_rtcp_func=sCreateRtpTransport; mTransportFactories.audio_rtcp_func_data=this; @@ -237,6 +249,9 @@ TunnelManager::~TunnelManager(){ } void TunnelManager::stopClient(){ +#ifdef USE_BELLESIP + sal_disable_tunnel(mCore->sal); +#else eXosip_transport_hook_register(NULL); if (mSipSocket != NULL){ sMutex.lock(); @@ -244,6 +259,7 @@ void TunnelManager::stopClient(){ mSipSocket = NULL; sMutex.unlock(); } +#endif if (mTunnelClient){ delete mTunnelClient; mTunnelClient=NULL; @@ -258,16 +274,9 @@ void TunnelManager::processTunnelEvent(const Event &ev){ ms_message("Tunnel is up, registering now"); linphone_core_set_firewall_policy(mCore,LinphonePolicyNoFirewall); linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories); - eXosip_transport_hook_register(&mExosipTransport); - //force transport to udp - LCSipTransports lTransport; - - lTransport.udp_port=(0xDFFF&random())+1024; - lTransport.tcp_port=0; - lTransport.tls_port=0; - lTransport.dtls_port=0; - - linphone_core_set_sip_transports(mCore, &lTransport); + + sal_enable_tunnel(mCore->sal, mTunnelClient); + //register if (lProxy) { linphone_proxy_config_done(lProxy); @@ -323,7 +332,15 @@ void TunnelManager::enable(bool isEnable) { mReady=false; linphone_core_set_rtp_transport_factories(mCore,NULL); - eXosip_transport_hook_register(NULL); + sal_disable_tunnel(mCore->sal); + // Set empty transports to force the setting of regular transport, otherwise it is not applied + LCSipTransports lTransport; + lTransport.udp_port = 0; + lTransport.tcp_port = 0; + lTransport.tls_port = 0; + lTransport.dtls_port = 0; + linphone_core_set_sip_transports(mCore, &lTransport); + //Restore transport and firewall policy linphone_core_set_sip_transports(mCore, &mRegularTransport); linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy); @@ -366,8 +383,12 @@ void TunnelManager::sOnIterate(TunnelManager *zis){ } #ifdef ANDROID -extern void linphone_android_log_handler(int prio, const char *fmt, va_list args); +extern void linphone_android_log_handler(int prio, char *str); static void linphone_android_tunnel_log_handler(int lev, const char *fmt, va_list args) { + char str[4096]; + vsnprintf(str, sizeof(str) - 1, fmt, args); + str[sizeof(str) - 1] = '\0'; + int prio; switch(lev){ case TUNNEL_DEBUG: prio = ANDROID_LOG_DEBUG; break; @@ -377,7 +398,7 @@ static void linphone_android_tunnel_log_handler(int lev, const char *fmt, va_lis case TUNNEL_ERROR: prio = ANDROID_LOG_ERROR; break; default: prio = ANDROID_LOG_DEFAULT; break; } - linphone_android_log_handler(prio, fmt, args); + linphone_android_log_handler(prio, str); } #endif /*ANDROID*/ @@ -390,7 +411,7 @@ void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) { #ifdef ANDROID else SetLogHandler(linphone_android_tunnel_log_handler); #else - else SetLogHandler(default_log_handler); + else SetLogHandler(tunnel_default_log_handler); #endif if (isEnabled) { diff --git a/coreapi/TunnelManager.hh b/coreapi/TunnelManager.hh index 113f76786..9ca29ad86 100644 --- a/coreapi/TunnelManager.hh +++ b/coreapi/TunnelManager.hh @@ -15,9 +15,12 @@ #include "tunnel/client.hh" #include "linphonecore.h" +#ifndef USE_BELLESIP extern "C" { #include "eXosip2/eXosip_transport_hook.h" } +#endif + namespace belledonnecomm { class TunnelClient; class UdpMirrorClient; @@ -159,8 +162,10 @@ class UdpMirrorClient; void postEvent(const Event &ev); LinphoneCore* mCore; LCSipTransports mRegularTransport; +#ifndef USE_BELLESIP TunnelSocket *mSipSocket; eXosip_transport_hooks_t mExosipTransport; +#endif StateCallback mCallback; void * mCallbackData; bool mEnabled; diff --git a/coreapi/address.c b/coreapi/address.c index ad07819bc..ec37255c1 100644 --- a/coreapi/address.c +++ b/coreapi/address.c @@ -32,7 +32,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. **/ LinphoneAddress * linphone_address_new(const char *addr){ SalAddress *saddr=sal_address_new(addr); - if (saddr==NULL) ms_error("Cannot create LinphoneAddress, bad uri [%s]",addr); + if (saddr==NULL) + ms_error("Cannot create LinphoneAddress, bad uri [%s]",addr); return saddr; } @@ -43,6 +44,20 @@ LinphoneAddress * linphone_address_clone(const LinphoneAddress *addr){ return sal_address_clone(addr); } +/** + * Increment reference count of LinphoneAddress object. +**/ +LinphoneAddress * linphone_address_ref(LinphoneAddress *addr){ + return sal_address_ref(addr); +} + +/** + * Decrement reference count of LinphoneAddress object. When dropped to zero, memory is freed. +**/ +void linphone_address_unref(LinphoneAddress *addr){ + sal_address_unref(addr); +} + /** * Returns the address scheme, normally "sip". **/ @@ -92,18 +107,26 @@ void linphone_address_set_domain(LinphoneAddress *uri, const char *host){ sal_address_set_domain(uri,host); } -/** - * Sets the port number. -**/ -void linphone_address_set_port(LinphoneAddress *uri, const char *port){ - sal_address_set_port(uri,port); -} /** * Sets the port number. **/ -void linphone_address_set_port_int(LinphoneAddress *uri, int port){ - sal_address_set_port_int(uri,port); +void linphone_address_set_port(LinphoneAddress *uri, int port){ + sal_address_set_port(uri,port); +} + +/** + * Set a transport. +**/ +void linphone_address_set_transport(LinphoneAddress *uri, LinphoneTransportType tp){ + sal_address_set_transport(uri,(SalTransport)tp); +} + +/** + * Get the transport. +**/ +LinphoneTransportType linphone_address_get_transport(const LinphoneAddress *uri){ + return (LinphoneTransportType)sal_address_get_transport(uri); } /** @@ -129,6 +152,13 @@ char *linphone_address_as_string_uri_only(const LinphoneAddress *u){ return sal_address_as_string_uri_only(u); } +/** + * Returns true if address refers to a secure location (sips) +**/ +bool_t linphone_address_is_secure(const LinphoneAddress *uri){ + return sal_address_is_secure(uri); +} + static bool_t strings_equals(const char *s1, const char *s2){ if (s1==NULL && s2==NULL) return TRUE; if (s1!=NULL && s2!=NULL && strcmp(s1,s2)==0) return TRUE; @@ -145,26 +175,33 @@ bool_t linphone_address_weak_equal(const LinphoneAddress *a1, const LinphoneAddr int p1,p2; u1=linphone_address_get_username(a1); u2=linphone_address_get_username(a2); - p1=linphone_address_get_port_int(a1); - p2=linphone_address_get_port_int(a2); + p1=linphone_address_get_port(a1); + p2=linphone_address_get_port(a2); h1=linphone_address_get_domain(a1); h2=linphone_address_get_domain(a2); return strings_equals(u1,u2) && strings_equals(h1,h2) && p1==p2; } /** - * Destroys a LinphoneAddress object. + * Destroys a LinphoneAddress object (actually calls linphone_address_unref()). **/ void linphone_address_destroy(LinphoneAddress *u){ - sal_address_destroy(u); + sal_address_unref(u); } -int linphone_address_get_port_int(const LinphoneAddress *u) { - return sal_address_get_port_int(u); -} +/** + * Get port number as an integer value. + */ -const char* linphone_address_get_port(const LinphoneAddress *u) { +/** + * Get port number, 0 if not present. + */ +int linphone_address_get_port(const LinphoneAddress *u) { return sal_address_get_port(u); } +LinphoneAddress * linphone_core_create_address(LinphoneCore *lc, const char *address) { + return linphone_address_new(address); +} + /** @} */ diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 8ab1c21ff..bd7849832 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -33,19 +33,26 @@ /** * Create a LinphoneAuthInfo object with supplied information. - * * The object can be created empty, that is with all arguments set to NULL. - * Username, userid, password and realm can be set later using specific methods. + * Username, userid, password, realm and domain can be set later using specific methods. + * At the end, username and passwd (or ha1) are required. + * @param username the username that needs to be authenticated + * @param userid the userid used for authenticating (use NULL if you don't know what it is) + * @param passwd the password in clear text + * @param ha1 the ha1-encrypted password if password is not given in clear text. + * @param realm the authentication domain (which can be larger than the sip domain. Unfortunately many SIP servers don't use this parameter. + * @param domain the SIP domain for which this authentication information is valid, if it has to be restricted for a single SIP domain. + * @return a #LinphoneAuthInfo. linphone_auth_info_destroy() must be used to destroy it when no longer needed. The LinphoneCore makes a copy of LinphoneAuthInfo + * passed through linphone_core_add_auth_info(). **/ -LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, - const char *passwd, const char *ha1,const char *realm) -{ +LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain){ LinphoneAuthInfo *obj=ms_new0(LinphoneAuthInfo,1); if (username!=NULL && (strlen(username)>0) ) obj->username=ms_strdup(username); if (userid!=NULL && (strlen(userid)>0)) obj->userid=ms_strdup(userid); if (passwd!=NULL && (strlen(passwd)>0)) obj->passwd=ms_strdup(passwd); 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; } @@ -57,6 +64,7 @@ static LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ if (ai->passwd) obj->passwd=ms_strdup(ai->passwd); 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; @@ -83,6 +91,11 @@ const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i){ const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *i){ return i->realm; } + +const char *linphone_auth_info_get_domain(const LinphoneAuthInfo *i){ + return i->domain; +} + const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i){ return i->ha1; } @@ -121,7 +134,7 @@ void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid){ } /** - * Sets realm. + * Set realm. **/ void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm){ if (info->realm){ @@ -130,6 +143,19 @@ void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm){ } if (realm && strlen(realm)>0) info->realm=ms_strdup(realm); } + +/** + * Set domain for which this authentication is valid. This should not be necessary because realm is supposed to be unique and sufficient. + * However, many SIP servers don't set realm correctly, then domain has to be used to distinguish between several SIP account bearing the same username. +**/ +void linphone_auth_info_set_domain(LinphoneAuthInfo *info, const char *domain){ + if (info->domain){ + ms_free(info->domain); + info->domain=NULL; + } + if (domain && strlen(domain)>0) info->domain=ms_strdup(domain); +} + /** * Sets ha1. **/ @@ -150,6 +176,7 @@ void linphone_auth_info_destroy(LinphoneAuthInfo *obj){ if (obj->passwd!=NULL) ms_free(obj->passwd); if (obj->ha1!=NULL) ms_free(obj->ha1); if (obj->realm!=NULL) ms_free(obj->realm); + if (obj->domain!=NULL) ms_free(obj->domain); ms_free(obj); } @@ -161,28 +188,36 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in if (obj==NULL || lp_config_get_int(config, "sip", "store_auth_info", 1) == 0){ return; - } + } + if (!obj->ha1 && obj->realm && obj->passwd && (obj->username||obj->userid) && lp_config_get_int(config, "sip", "store_ha1_passwd", 1) == 1) { + /*compute ha1 to avoid storing clear text password*/ + obj->ha1=ms_malloc(33); + sal_auth_compute_ha1(obj->userid?obj->userid:obj->username,obj->realm,obj->passwd,obj->ha1); + } if (obj->username!=NULL){ lp_config_set_string(config,key,"username",obj->username); } if (obj->userid!=NULL){ lp_config_set_string(config,key,"userid",obj->userid); } - if (obj->passwd!=NULL){ - lp_config_set_string(config,key,"passwd",obj->passwd); - } if (obj->ha1!=NULL){ lp_config_set_string(config,key,"ha1",obj->ha1); + } else if (obj->passwd!=NULL){ /*only write passwd if no ha1*/ + lp_config_set_string(config,key,"passwd",obj->passwd); } if (obj->realm!=NULL){ lp_config_set_string(config,key,"realm",obj->realm); } + if (obj->domain!=NULL){ + lp_config_set_string(config,key,"domain",obj->domain); + } } LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int pos) { char key[50]; - const char *username,*userid,*passwd,*ha1,*realm; + const char *username,*userid,*passwd,*ha1,*realm,*domain; + LinphoneAuthInfo *ret; sprintf(key,"auth_info_%i",pos); if (!lp_config_has_section(config,key)){ @@ -194,14 +229,9 @@ LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int passwd=lp_config_get_string(config,key,"passwd",NULL); ha1=lp_config_get_string(config,key,"ha1",NULL); realm=lp_config_get_string(config,key,"realm",NULL); - return linphone_auth_info_new(username,userid,passwd,ha1,realm); -} - -static bool_t key_match(const char *tmp1, const char *tmp2){ - if (tmp1==NULL && tmp2==NULL) return TRUE; - if (tmp1!=NULL && tmp2!=NULL && strcmp(tmp1,tmp2)==0) return TRUE; - return FALSE; - + domain=lp_config_get_string(config,key,"domain",NULL); + ret=linphone_auth_info_new(username,userid,passwd,ha1,realm,domain); + return ret; } static char * remove_quotes(char * input){ @@ -230,41 +260,62 @@ static int realm_match(const char *realm1, const char *realm2){ return FALSE; } -/** - * Retrieves a LinphoneAuthInfo previously entered into the LinphoneCore. -**/ -const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username) -{ +static const LinphoneAuthInfo *find_auth_info(LinphoneCore *lc, const char *username, const char *realm, const char *domain){ MSList *elem; - LinphoneAuthInfo *ret=NULL,*candidate=NULL; - for (elem=lc->auth_info;elem!=NULL;elem=elem->next){ - LinphoneAuthInfo *pinfo=(LinphoneAuthInfo*)elem->data; - if (realm==NULL){ - /*return the authinfo for any realm provided that there is only one for that username*/ - if (key_match(pinfo->username,username)){ - if (ret!=NULL){ - ms_warning("There are several auth info for username '%s'",username); - return NULL; + const LinphoneAuthInfo *ret=NULL; + + for (elem=lc->auth_info;elem!=NULL;elem=elem->next) { + LinphoneAuthInfo *pinfo = (LinphoneAuthInfo*)elem->data; + if (username && pinfo->username && strcmp(username,pinfo->username)==0) { + if (realm && domain){ + if (pinfo->realm && strcmp(realm,pinfo->realm)==0 + && pinfo->domain && strcmp(domain,pinfo->domain)==0) { + return pinfo; } - ret=pinfo; - } - }else{ - /*return the exact authinfo, or an authinfo for which realm was not supplied yet*/ - if (pinfo->realm!=NULL){ - if (realm_match(pinfo->realm,realm) - && key_match(pinfo->username,username)) + } else if (realm) { + if (pinfo->realm && realm_match(realm,pinfo->realm)) { + if (ret!=NULL) { + ms_warning("Non unique realm found for %s",username); + return NULL; + } ret=pinfo; - }else{ - if (key_match(pinfo->username,username)) - candidate=pinfo; + } + } else if (domain && pinfo->domain && strcmp(domain,pinfo->domain)==0) { + return pinfo; + } else if (!domain) { + return pinfo; } } } - if (ret==NULL && candidate!=NULL) - ret=candidate; return ret; } +/** + * Find authentication info matching realm, username, domain criterias. + * First of all, (realm,username) pair are searched. If multiple results (which should not happen because realm are supposed to be unique), then domain is added to the search. + * @param lc the LinphoneCore + * @param realm the authentication 'realm' (optional) + * @param username the SIP username to be authenticated (mandatory) + * @param domain the SIP domain name (optional) + * @return a #LinphoneAuthInfo +**/ +const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain){ + const LinphoneAuthInfo *ai=NULL; + if (realm){ + ai=find_auth_info(lc,username,realm,NULL); + if (ai==NULL && domain){ + ai=find_auth_info(lc,username,realm,domain); + } + } + if (ai == NULL && domain != NULL) { + ai=find_auth_info(lc,username,NULL,domain); + } + if (ai==NULL){ + ai=find_auth_info(lc,username,NULL,NULL); + } + return ai; +} + static void write_auth_infos(LinphoneCore *lc){ MSList *elem; int i; @@ -277,6 +328,10 @@ static void write_auth_infos(LinphoneCore *lc){ linphone_auth_info_write_config(lc->config,NULL,i); /* mark the end */ } +LinphoneAuthInfo * linphone_core_create_auth_info(LinphoneCore *lc, const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain) { + return linphone_auth_info_new(username, userid, passwd, ha1, realm, domain); +} + /** * Adds authentication information to the LinphoneCore. * @@ -289,25 +344,33 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) MSList *l; /* find if we are attempting to modify an existing auth info */ - ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username); - if (ai!=NULL){ + 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); } 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){ - const char *username,*realm; SalOp *op=(SalOp*)elem->data; LinphoneAuthInfo *ai; - sal_op_get_auth_requested(op,&realm,&username); - ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username); + const SalAuthInfo *req_sai=sal_op_get_auth_requested(op); + ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,req_sai->realm,req_sai->username,req_sai->domain); if (ai){ SalAuthInfo sai; + MSList* proxy; sai.username=ai->username; sai.userid=ai->userid; sai.realm=ai->realm; sai.password=ai->passwd; + sai.ha1=ai->ha1; + /*proxy case*/ + for (proxy=(MSList*)linphone_core_get_proxy_config_list(lc);proxy!=NULL;proxy=proxy->next) { + if (proxy->data == sal_op_get_user_pointer(op)) { + linphone_proxy_config_set_state((LinphoneProxyConfig*)(proxy->data),LinphoneRegistrationProgress,"Authentication..."); + break; + } + } sal_op_authenticate(op,&sai); ai->usecount++; } @@ -329,7 +392,7 @@ void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *inf **/ void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info){ LinphoneAuthInfo *r; - r=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username); + r=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); if (r){ lc->auth_info=ms_list_remove(lc->auth_info,r); /*printf("len=%i newlen=%i\n",len,newlen);*/ diff --git a/coreapi/bellesip_sal/sal_address_impl.c b/coreapi/bellesip_sal/sal_address_impl.c new file mode 100644 index 000000000..91c2d91c8 --- /dev/null +++ b/coreapi/bellesip_sal/sal_address_impl.c @@ -0,0 +1,174 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" +/**/ +/* Address manipulation API*/ +SalAddress * sal_address_new(const char *uri){ + belle_sip_header_address_t* result; + if (uri) { + result=belle_sip_header_address_parse (uri); + /*may return NULL*/ + } else { + result = belle_sip_header_address_new(); + belle_sip_header_address_set_uri(result,belle_sip_uri_new()); + } + 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); + if (uri) { + if (belle_sip_uri_is_secure(uri)) return "sips"; + else return "sip"; + } else + return NULL; +} + +bool_t sal_address_is_secure(const SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + if (uri) return belle_sip_uri_is_secure(uri); + return FALSE; +} + +const char *sal_address_get_display_name(const SalAddress* addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + return belle_sip_header_address_get_displayname(header_addr); + +} +const char *sal_address_get_display_name_unquoted(const SalAddress *addr){ + return sal_address_get_display_name(addr); +} +#define SAL_ADDRESS_GET(addr,param) \ +{belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);\ +belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);\ +if (uri) {\ + return belle_sip_uri_get_##param(uri);\ +} else\ + return NULL;} + +#define SAL_ADDRESS_SET(addr,param,value) {\ +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);\ +belle_sip_uri_set_##param(uri,value);} + +const char *sal_address_get_username(const SalAddress *addr){ + SAL_ADDRESS_GET(addr,user) +} +const char *sal_address_get_domain(const SalAddress *addr){ + SAL_ADDRESS_GET(addr,host) +} +int sal_address_get_port(const SalAddress *addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + if (uri) { + return belle_sip_uri_get_port(uri); + } else + return -1; +} +SalTransport sal_address_get_transport(const SalAddress* addr){ + const char *transport=sal_address_get_transport_name(addr); + if (transport) + return sal_transport_parse(transport); + else + return SalTransportUDP; +}; + +const char* sal_address_get_transport_name(const SalAddress* addr){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr); + if (uri) { + return belle_sip_uri_get_transport_param(uri); + } + return NULL; +} + +void sal_address_set_display_name(SalAddress *addr, const char *display_name){ + belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr); + belle_sip_header_address_set_displayname(header_addr,display_name); +} + +void sal_address_set_username(SalAddress *addr, const char *username){ + SAL_ADDRESS_SET(addr,user,username); +} + +void sal_address_set_domain(SalAddress *addr, const char *host){ + SAL_ADDRESS_SET(addr,host,host); +} + +void sal_address_set_port(SalAddress *addr, int port){ + SAL_ADDRESS_SET(addr,port,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)); + belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(header_addr)); + return ; +} + +char *sal_address_as_string(const SalAddress *addr){ + char tmp[1024]={0}; + size_t off=0; + belle_sip_object_marshal((belle_sip_object_t*)addr,tmp,sizeof(tmp),&off); + return ms_strdup(tmp); +} + +char *sal_address_as_string_uri_only(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); + char tmp[1024]={0}; + size_t off=0; + belle_sip_object_marshal((belle_sip_object_t*)uri,tmp,sizeof(tmp),&off); + return ms_strdup(tmp); +} + +void sal_address_set_param(SalAddress *addr,const char* name,const char* value){ + belle_sip_parameters_t* parameters = BELLE_SIP_PARAMETERS(addr); + belle_sip_parameters_set_parameter(parameters,name,value); + return ; +} + +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)); + } +} + +void sal_address_set_transport_name(SalAddress* addr,const char *transport){ + SAL_ADDRESS_SET(addr,transport_param,transport); +} + +SalAddress *sal_address_ref(SalAddress *addr){ + return (SalAddress*)belle_sip_object_ref(BELLE_SIP_HEADER_ADDRESS(addr)); +} + +void sal_address_unref(SalAddress *addr){ + belle_sip_object_unref(BELLE_SIP_HEADER_ADDRESS(addr)); +} + +void sal_address_destroy(SalAddress *addr){ + sal_address_unref(addr); +} + diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c new file mode 100644 index 000000000..37384f3e9 --- /dev/null +++ b/coreapi/bellesip_sal/sal_impl.c @@ -0,0 +1,919 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sal_impl.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +typedef struct belle_sip_certificates_chain_t _SalCertificatesChain; +typedef struct belle_sip_signing_key_t _SalSigningKey; + +/* +rfc3323 +4.2 Expressing Privacy Preferences +When a Privacy header is constructed, it MUST consist of either the + value 'none', or one or more of the values 'user', 'header' and + 'session' (each of which MUST appear at most once) which MAY in turn + be followed by the 'critical' indicator. + */ +void sal_op_set_privacy_from_message(SalOp* op,belle_sip_message_t* msg) { + belle_sip_header_privacy_t* privacy = belle_sip_message_get_header_by_type(msg,belle_sip_header_privacy_t); + if (!privacy) { + sal_op_set_privacy(op,SalPrivacyNone); + } else { + belle_sip_list_t* privacy_list=belle_sip_header_privacy_get_privacy(privacy); + sal_op_set_privacy(op,0); + for (;privacy_list!=NULL;privacy_list=privacy_list->next) { + char* privacy_value=(char*)privacy_list->data; + if(strcmp(sal_privacy_to_string(SalPrivacyCritical),privacy_value) == 0) + sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyCritical); + if(strcmp(sal_privacy_to_string(SalPrivacyHeader),privacy_value) == 0) + sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyHeader); + if(strcmp(sal_privacy_to_string(SalPrivacyId),privacy_value) == 0) + sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyId); + if(strcmp(sal_privacy_to_string(SalPrivacyNone),privacy_value) == 0) { + sal_op_set_privacy(op,SalPrivacyNone); + break; + } + if(strcmp(sal_privacy_to_string(SalPrivacySession),privacy_value) == 0) + sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacySession); + if(strcmp(sal_privacy_to_string(SalPrivacyUser),privacy_value) == 0) + sal_op_set_privacy(op,sal_op_get_privacy(op)|SalPrivacyUser); + } + } +} +static void set_tls_properties(Sal *ctx); + +void _belle_sip_log(belle_sip_log_level lev, const char *fmt, va_list args) { + int ortp_level; + switch(lev) { + case BELLE_SIP_LOG_FATAL: + ortp_level=ORTP_FATAL; + break; + case BELLE_SIP_LOG_ERROR: + ortp_level=ORTP_ERROR; + break; + case BELLE_SIP_LOG_WARNING: + ortp_level=ORTP_WARNING; + break; + case BELLE_SIP_LOG_MESSAGE: + ortp_level=ORTP_MESSAGE; + break; + case BELLE_SIP_LOG_DEBUG: + default: + ortp_level=ORTP_DEBUG; + break; + } + if (ortp_log_level_enabled(ortp_level)){ + ortp_logv(ortp_level,fmt,args); + } +} + +void sal_enable_logs(){ + belle_sip_set_log_level(BELLE_SIP_LOG_MESSAGE); +} + +void sal_disable_logs() { + belle_sip_set_log_level(BELLE_SIP_LOG_ERROR); +} + +void sal_add_pending_auth(Sal *sal, SalOp *op){ + if (ms_list_find(sal->pending_auths,op)==NULL){ + sal->pending_auths=ms_list_append(sal->pending_auths,sal_op_ref(op)); + } +} + +void sal_remove_pending_auth(Sal *sal, SalOp *op){ + if (ms_list_find(sal->pending_auths,op)){ + sal->pending_auths=ms_list_remove(sal->pending_auths,op); + sal_op_unref(op); + } +} + +void sal_process_authentication(SalOp *op) { + belle_sip_request_t* initial_request=belle_sip_transaction_get_request((belle_sip_transaction_t*)op->pending_auth_transaction); + belle_sip_request_t* new_request; + bool_t is_within_dialog=FALSE; + 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); + + sal_add_pending_auth(op->base.root,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) + new_request = belle_sip_dialog_create_queued_request_from(op->dialog,initial_request); + is_within_dialog=TRUE; + } else { + new_request=initial_request; + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_AUTHORIZATION); + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(new_request),BELLE_SIP_PROXY_AUTHORIZATION); + } + if (new_request==NULL) { + ms_error("sal_process_authentication() op=[%p] cannot obtain new request from dialog.",op); + return; + } + + if (belle_sip_provider_add_authorization(op->base.root->prov,new_request,response,&auth_list)) { + if (is_within_dialog) { + sal_op_send_request(op,new_request); + } else { + sal_op_resend_request(op,new_request); + } + sal_remove_pending_auth(op->base.root,op); + }else { + ms_message("No auth info found for [%s]",sal_op_get_from(op)); + if (is_within_dialog) { + belle_sip_object_unref(new_request); + } + if (op->auth_info) sal_auth_info_delete(op->auth_info); + 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); + } else { + ms_error("sal process_dialog_terminated no op found for this dialog [%p], ignoring",dialog); + } +} + +static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + belle_sip_client_transaction_t*client_transaction; + SalOp* op; + 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); + } + } else { + /*ms_error("sal process_io_error not implemented yet for non transaction");*/ + /*nop, because already handle at transaction layer*/ + } +} + +static void process_request_event(void *ud, const belle_sip_request_event_t *event) { + Sal *sal=(Sal*)ud; + SalOp* op=NULL; + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_dialog_t* dialog=belle_sip_request_event_get_dialog(event); + belle_sip_header_address_t* origin_address; + belle_sip_header_address_t* address; + belle_sip_header_from_t* from_header; + belle_sip_header_to_t* to; + belle_sip_response_t* resp; + belle_sip_header_t *evh; + const char *method=belle_sip_request_get_method(req); + + from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); + + if (dialog) { + op=(SalOp*)belle_sip_dialog_get_application_data(dialog); + if (op==NULL || op->state==SalOpStateTerminated){ + ms_warning("Receiving request for null or terminated op [%p], ignored",op); + return; + } + }else if (strcmp("INVITE",method)==0) { + op=sal_op_new(sal); + op->dir=SalOpDirIncoming; + sal_op_call_fill_cbs(op); + }else if ((strcmp("SUBSCRIBE",method)==0 || strcmp("NOTIFY",method)==0) && (evh=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"))!=NULL) { + op=sal_op_new(sal); + op->dir=SalOpDirIncoming; + if (strncmp(belle_sip_header_get_unparsed_value(evh),"presence",strlen("presence"))==0){ + sal_op_presence_fill_cbs(op); + }else + sal_op_subscribe_fill_cbs(op); + }else if (strcmp("MESSAGE",method)==0) { + op=sal_op_new(sal); + op->dir=SalOpDirIncoming; + sal_op_message_fill_cbs(op); + }else if (strcmp("OPTIONS",method)==0) { + resp=belle_sip_response_create_from_request(req,200); + belle_sip_provider_send_response(sal->prov,resp); + return; + }else if (strcmp("INFO",method)==0) { + resp=belle_sip_response_create_from_request(req,481);/*INFO out of call dialogs are not allowed*/ + belle_sip_provider_send_response(sal->prov,resp); + return; + }else if (strcmp("BYE",method)==0) { + resp=belle_sip_response_create_from_request(req,481);/*out of dialog BYE */ + belle_sip_provider_send_response(sal->prov,resp); + return; + }else if (strcmp("CANCEL",method)==0) { + resp=belle_sip_response_create_from_request(req,481);/*out of dialog CANCEL */ + belle_sip_provider_send_response(sal->prov,resp); + return; + }else if (sal->enable_test_features && strcmp("PUBLISH",method)==0) { + resp=belle_sip_response_create_from_request(req,200);/*out of dialog BYE */ + belle_sip_message_add_header((belle_sip_message_t*)resp,belle_sip_header_create("SIP-Etag","4441929FFFZQOA")); + belle_sip_provider_send_response(sal->prov,resp); + 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); + belle_sip_provider_send_response(sal->prov,resp); + return; + } + + if (!op->base.from_address) { + 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))); + sal_op_set_from_address(op,(SalAddress*)address); + belle_sip_object_unref(address); + } + + + if (!op->base.to_address) { + to=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_to_t); + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(to)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to))); + sal_op_set_to_address(op,(SalAddress*)address); + belle_sip_object_unref(address); + } + + if (!op->base.origin) { + /*set origin uri*/ + origin_address=belle_sip_header_address_create(NULL,belle_sip_request_extract_origin(req)); + __sal_op_set_network_origin_address(op,(SalAddress*)origin_address); + belle_sip_object_unref(origin_address); + } + if (!op->base.remote_ua) { + sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(req)); + } + + 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(req), belle_sip_header_call_id_t)))); + } + /*It is worth noting that proxies can (and + will) remove this header field*/ + 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); + } else { + ms_error("sal process_request_event not implemented yet"); + } + +} + +static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){ + belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); + belle_sip_response_t* response = belle_sip_response_event_get_response(event); + int response_code = belle_sip_response_get_status_code(response); + + if (!client_transaction) { + ms_warning("Discarding stateless response [%i]",response_code); + return; + } 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)); + + if (op->state == SalOpStateTerminated) { + belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); + return; + } + if (!op->base.remote_ua) { + sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); + } + 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) { + /*handle authorization*/ + switch (response_code) { + case 200: + break; + case 401: + case 407: + /*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/ + if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { + /*only bye are completed*/ + belle_sip_message("Op is in state terminating, nothing else to do "); + } else { + if (op->pending_auth_transaction){ + 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; + } + 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); + } else { + ms_error("Unhandled event response [%p]",event); + } + } + +} +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); + } else { + ms_error("Unhandled event timeout [%p]",event); + } +} +static void process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + belle_sip_client_transaction_t* client_transaction = belle_sip_transaction_terminated_event_get_client_transaction(event); + belle_sip_server_transaction_t* server_transaction = belle_sip_transaction_terminated_event_get_server_transaction(event); + belle_sip_transaction_t* trans; + SalOp* op; + + if(client_transaction) + trans=BELLE_SIP_TRANSACTION(client_transaction); + else + 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); + } else { + ms_message("Unhandled transaction terminated [%p]",trans); + } + if (op && client_transaction) sal_op_unref(op); /*because every client transaction ref op*/ + +} + + +static void process_auth_requested(void *sal, belle_sip_auth_event_t *event) { + SalAuthInfo* auth_info = sal_auth_info_create(event); + ((Sal*)sal)->callbacks.auth_requested(sal,auth_info); + belle_sip_auth_event_set_passwd(event,(const char*)auth_info->password); + belle_sip_auth_event_set_ha1(event,(const char*)auth_info->ha1); + belle_sip_auth_event_set_userid(event,(const char*)auth_info->userid); + belle_sip_auth_event_set_signing_key(event,(belle_sip_signing_key_t *)auth_info->key); + belle_sip_auth_event_set_client_certificates_chain(event,(belle_sip_certificates_chain_t* )auth_info->certificates); + sal_auth_info_delete(auth_info); +} + +Sal * sal_init(){ + belle_sip_listener_callbacks_t listener_callbacks; + Sal * sal=ms_new0(Sal,1); + sal->auto_contacts=TRUE; + sal->user_agent=belle_sip_header_user_agent_new(); +#if defined(PACKAGE_NAME) && defined(LINPHONE_VERSION) + belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION); +#endif + sal_append_stack_string_to_user_agent(sal); + belle_sip_object_ref(sal->user_agent); + belle_sip_set_log_handler(_belle_sip_log); + sal->stack = belle_sip_stack_new(NULL); + sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); + sal_nat_helper_enable(sal,TRUE); + memset(&listener_callbacks,0,sizeof(listener_callbacks)); + listener_callbacks.process_dialog_terminated=process_dialog_terminated; + listener_callbacks.process_io_error=process_io_error; + listener_callbacks.process_request_event=process_request_event; + listener_callbacks.process_response_event=process_response_event; + listener_callbacks.process_timeout=process_timeout; + listener_callbacks.process_transaction_terminated=process_transaction_terminated; + listener_callbacks.process_auth_requested=process_auth_requested; + sal->listener=belle_sip_listener_create_from_callbacks(&listener_callbacks,sal); + belle_sip_provider_add_sip_listener(sal->prov,sal->listener); + sal->tls_verify=TRUE; + sal->tls_verify_cn=TRUE; + 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; +} + +void *sal_get_user_pointer(const Sal *sal){ + return sal->up; +} + +static void unimplemented_stub(){ + ms_warning("Unimplemented SAL callback"); +} + +void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ + memcpy(&ctx->callbacks,cbs,sizeof(*cbs)); + if (ctx->callbacks.call_received==NULL) + ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub; + if (ctx->callbacks.call_ringing==NULL) + ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub; + if (ctx->callbacks.call_accepted==NULL) + ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub; + if (ctx->callbacks.call_failure==NULL) + ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub; + if (ctx->callbacks.call_terminated==NULL) + ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub; + if (ctx->callbacks.call_released==NULL) + ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub; + if (ctx->callbacks.call_updating==NULL) + ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub; + if (ctx->callbacks.auth_failure==NULL) + ctx->callbacks.auth_failure=(SalOnAuthFailure)unimplemented_stub; + if (ctx->callbacks.register_success==NULL) + ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub; + if (ctx->callbacks.register_failure==NULL) + ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub; + if (ctx->callbacks.dtmf_received==NULL) + ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub; + if (ctx->callbacks.notify==NULL) + ctx->callbacks.notify=(SalOnNotify)unimplemented_stub; + if (ctx->callbacks.subscribe_received==NULL) + ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub; + if (ctx->callbacks.subscribe_closed==NULL) + ctx->callbacks.subscribe_closed=(SalOnSubscribeClosed)unimplemented_stub; + if (ctx->callbacks.parse_presence_requested==NULL) + ctx->callbacks.parse_presence_requested=(SalOnParsePresenceRequested)unimplemented_stub; + if (ctx->callbacks.convert_presence_to_xml_requested==NULL) + ctx->callbacks.convert_presence_to_xml_requested=(SalOnConvertPresenceToXMLRequested)unimplemented_stub; + if (ctx->callbacks.notify_presence==NULL) + ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub; + if (ctx->callbacks.subscribe_presence_received==NULL) + ctx->callbacks.subscribe_presence_received=(SalOnSubscribePresenceReceived)unimplemented_stub; + if (ctx->callbacks.text_received==NULL) + ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; + if (ctx->callbacks.ping_reply==NULL) + ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; + if (ctx->callbacks.auth_requested==NULL) + ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub; + if (ctx->callbacks.info_received==NULL) + ctx->callbacks.info_received=(SalOnInfoReceived)unimplemented_stub; + if (ctx->callbacks.on_publish_response==NULL) + ctx->callbacks.on_publish_response=(SalOnPublishResponse)unimplemented_stub; + if (ctx->callbacks.on_expire==NULL) + ctx->callbacks.on_expire=(SalOnExpire)unimplemented_stub; +} + + + +void sal_uninit(Sal* sal){ + belle_sip_object_unref(sal->user_agent); + belle_sip_object_unref(sal->prov); + belle_sip_object_unref(sal->stack); + belle_sip_object_unref(sal->listener); + if (sal->uuid) ms_free(sal->uuid); + if (sal->root_ca) ms_free(sal->root_ca); + ms_free(sal); +}; + +int sal_transport_available(Sal *sal, SalTransport t){ + switch(t){ + case SalTransportUDP: + case SalTransportTCP: + return TRUE; + case SalTransportTLS: + return belle_sip_stack_tls_available(sal->stack); + case SalTransportDTLS: + return FALSE; + } + return FALSE; +} + +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))); + 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); + } else { + return -1; + } + return result; +} + +int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure) { + SalAddress* sal_addr = sal_address_new(NULL); + int result; + sal_address_set_domain(sal_addr,addr); + sal_address_set_port(sal_addr,port); + sal_address_set_transport(sal_addr,tr); + result = sal_add_listen_port(ctx,sal_addr); + 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_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); + return ; +} + +void sal_append_stack_string_to_user_agent(Sal *ctx) { + char stack_string[64]; + snprintf(stack_string, sizeof(stack_string) - 1, "(belle-sip/%s)", belle_sip_version_to_string()); + belle_sip_header_user_agent_add_product(ctx->user_agent, stack_string); +} + +/*keepalive period in ms*/ +void sal_set_keepalive_period(Sal *ctx,unsigned int value){ + const belle_sip_list_t* iterator; + belle_sip_listening_point_t* lp; + ctx->keep_alive=value; + for (iterator=belle_sip_provider_get_listening_points(ctx->prov);iterator!=NULL;iterator=iterator->next) { + lp=(belle_sip_listening_point_t*)iterator->data; + if (ctx->use_tcp_tls_keep_alive || strcasecmp(belle_sip_listening_point_get_transport(lp),"udp")==0) { + belle_sip_listening_point_set_keep_alive(lp,ctx->keep_alive); + } + } + return ; +} +int sal_enable_tunnel(Sal *ctx, void *tunnelclient) { +#ifdef TUNNEL_ENABLED + belle_sip_listening_point_t *lp; + int result; + + sal_unlisten_ports(ctx); + lp = belle_sip_tunnel_listening_point_new(ctx->stack, tunnelclient); + if (lp == NULL) return -1; + + 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); + return result; +#else + return 0; +#endif +} +void sal_disable_tunnel(Sal *ctx) { +#ifdef TUNNEL_ENABLED + sal_unlisten_ports(ctx); +#endif +} +/** + * returns keepalive period in ms + * 0 desactiaved + * */ +unsigned int sal_get_keepalive_period(Sal *ctx){ + return ctx->keep_alive; +} +void sal_use_session_timers(Sal *ctx, int expires){ + ctx->session_expires=expires; + return ; +} + +void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){ + ctx->one_matching_codec=one_matching_codec; +} + +void sal_use_rport(Sal *ctx, bool_t use_rports){ + belle_sip_provider_enable_rport(ctx->prov,use_rports); + ms_message("Sal use rport [%s]",use_rports?"enabled":"disabled"); + return ; +} + +static void set_tls_properties(Sal *ctx){ + belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov,"TLS"); + if (lp){ + belle_sip_tls_listening_point_t *tlp=BELLE_SIP_TLS_LISTENING_POINT(lp); + int verify_exceptions=0; + + if (!ctx->tls_verify) verify_exceptions=BELLE_SIP_TLS_LISTENING_POINT_BADCERT_ANY_REASON; + else if (!ctx->tls_verify_cn) verify_exceptions=BELLE_SIP_TLS_LISTENING_POINT_BADCERT_CN_MISMATCH; + + belle_sip_tls_listening_point_set_root_ca(tlp,ctx->root_ca); /*root_ca might be NULL */ + belle_sip_tls_listening_point_set_verify_exceptions(tlp,verify_exceptions); + } +} + +void sal_set_root_ca(Sal* ctx, const char* rootCa){ + if (ctx->root_ca){ + ms_free(ctx->root_ca); + ctx->root_ca=NULL; + } + if (rootCa) + ctx->root_ca=ms_strdup(rootCa); + set_tls_properties(ctx); + return ; +} + +void sal_verify_server_certificates(Sal *ctx, bool_t verify){ + ctx->tls_verify=verify; + set_tls_properties(ctx); + return ; +} + +void sal_verify_server_cn(Sal *ctx, bool_t verify){ + ctx->tls_verify_cn=verify; + set_tls_properties(ctx); + return ; +} + +void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) { + ctx->use_tcp_tls_keep_alive=enabled; +} + +int sal_iterate(Sal *sal){ + belle_sip_stack_sleep(sal->stack,0); + return 0; +} +MSList * sal_get_pending_auths(Sal *sal){ + return ms_list_copy(sal->pending_auths); +} + +#define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); +#define payload_type_get_number(pt) ((int)(long)(pt)->user_data) + +/*misc*/ +void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen){ + strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen); + ms_error("sal_get_default_local_ip() is deprecated."); +} + +const char *sal_get_root_ca(Sal* ctx) { + return ctx->root_ca; +} + +int sal_reset_transports(Sal *ctx){ + ms_message("Reseting transports"); + belle_sip_provider_clean_channels(ctx->prov); + return 0; +} + +void sal_set_dscp(Sal *ctx, int dscp){ + belle_sip_stack_set_default_dscp(ctx->stack,dscp); +} + +void sal_set_send_error(Sal *sal,int value) { + belle_sip_stack_set_send_error(sal->stack,value); +} +void sal_set_recv_error(Sal *sal,int value) { + belle_sip_provider_set_recv_error(sal->prov,value); +} +void sal_nat_helper_enable(Sal *sal,bool_t enable) { + sal->nat_helper_enabled=enable; + belle_sip_provider_enable_nat_helper(sal->prov,enable); + ms_message("Sal nat helper [%s]",enable?"enabled":"disabled"); +} +bool_t sal_nat_helper_enabled(Sal *sal) { + return sal->nat_helper_enabled; +} +void sal_set_dns_timeout(Sal* sal,int timeout) { + belle_sip_stack_set_dns_timeout(sal->stack, timeout); +} +int sal_get_dns_timeout(const Sal* sal) { + return belle_sip_stack_get_dns_timeout(sal->stack); +} +void sal_enable_dns_srv(Sal *sal, bool_t enable) { + belle_sip_stack_enable_dns_srv(sal->stack, (unsigned char)enable); +} +bool_t sal_dns_srv_enabled(const Sal *sal) { + return (bool_t)belle_sip_stack_dns_srv_enabled(sal->stack); +} + +void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file) { + belle_sip_stack_set_dns_user_hosts_file(sal->stack, hosts_file); +} + +const char * sal_get_dns_user_hosts_file(const Sal *sal) { + return belle_sip_stack_get_dns_user_hosts_file(sal->stack); +} + +SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) { + SalAuthInfo* auth_info = sal_auth_info_new(); + auth_info->realm = ms_strdup(belle_sip_auth_event_get_realm(event)); + auth_info->username = ms_strdup(belle_sip_auth_event_get_username(event)); + auth_info->domain = ms_strdup(belle_sip_auth_event_get_domain(event)); + auth_info->mode = (SalAuthMode)belle_sip_auth_event_get_mode(event); + return auth_info; +} + +SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info) { return auth_info->mode; } +SalSigningKey *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info) { return auth_info->key; } +SalCertificatesChain *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info) { return auth_info->certificates; } +void sal_auth_info_set_mode(SalAuthInfo* auth_info, SalAuthMode mode) { auth_info->mode = mode; } +void sal_certificates_chain_delete(SalCertificatesChain *chain) { + belle_sip_object_unref((belle_sip_object_t *)chain); +} +void sal_signing_key_delete(SalSigningKey *key) { + belle_sip_object_unref((belle_sip_object_t *)key); +} + +const char* sal_op_type_to_string(const SalOpType type) { + switch(type) { + case SalOpRegister: return "SalOpRegister"; + case SalOpCall: return "SalOpCall"; + case SalOpMessage: return "SalOpMessage"; + case SalOpPresence: return "SalOpPresence"; + default: + return "SalOpUnknown"; + } +} + +void sal_use_dates(Sal *ctx, bool_t enabled){ + ctx->use_dates=enabled; +} + +int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]) { + return belle_sip_auth_helper_compute_ha1(userid, realm, password, ha1); +} + + +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); + if (h==NULL){ + belle_sip_error("Fail to parse extension header."); + return (SalCustomHeader*)msg; + } + belle_sip_message_add_header(msg,h); + return (SalCustomHeader*)msg; +} + +const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ + if (ch){ + 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 NULL; +} + +void sal_custom_header_free(SalCustomHeader *ch){ + if (ch==NULL) return; + belle_sip_object_unref((belle_sip_message_t*)ch); +} + +SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch){ + if (ch==NULL) return NULL; + return (SalCustomHeader*)belle_sip_object_ref((belle_sip_message_t*)ch); +} + +const SalCustomHeader *sal_op_get_recv_custom_header(SalOp *op){ + SalOpBase *b=(SalOpBase *)op; + return b->recv_custom_headers; +} + +void sal_set_uuid(Sal *sal, const char *uuid){ + if (sal->uuid){ + belle_sip_free(sal->uuid); + sal->uuid=NULL; + } + if (uuid) + sal->uuid=belle_sip_strdup(uuid); +} + +typedef struct { + unsigned int time_low; + unsigned short time_mid; + unsigned short time_hi_and_version; + unsigned char clock_seq_hi_and_reserved; + unsigned char clock_seq_low; + unsigned char node[6]; +} sal_uuid_t; + + +int sal_create_uuid(Sal*ctx, char *uuid, size_t len){ + sal_uuid_t uuid_struct; + int i; + int written; + + if (len==0) return -1; + /*create an UUID as described in RFC4122, 4.4 */ + belle_sip_random_bytes((unsigned char*)&uuid_struct, sizeof(sal_uuid_t)); + uuid_struct.clock_seq_hi_and_reserved&=~(1<<6); + uuid_struct.clock_seq_hi_and_reserved|=1<<7; + uuid_struct.time_hi_and_version&=~(0xf<<12); + uuid_struct.time_hi_and_version|=4<<12; + + written=snprintf(uuid,len,"%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", uuid_struct.time_low, uuid_struct.time_mid, + uuid_struct.time_hi_and_version, uuid_struct.clock_seq_hi_and_reserved, + uuid_struct.clock_seq_low); + if (written>len+13){ + ms_error("sal_create_uuid(): buffer is too short !"); + return -1; + } + for (i = 0; i < 6; i++) + written+=snprintf(uuid+written,len-written,"%2.2x", uuid_struct.node[i]); + uuid[len-1]='\0'; + sal_set_uuid(ctx,uuid); + return 0; +} + +belle_sip_response_t* sal_create_response_from_request ( Sal* sal, belle_sip_request_t* req, int code ) { + belle_sip_response_t *resp=belle_sip_response_create_from_request(req,code); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(sal->user_agent)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),sal_make_supported_header(sal)); + return resp; +} + +void sal_set_refresher_retry_after(Sal *sal,int value) { + sal->refresher_retry_after=value; +} + +int sal_get_refresher_retry_after(const Sal *sal) { + return sal->refresher_retry_after; +} + +void sal_enable_auto_contacts(Sal *ctx, bool_t enabled){ + ctx->auto_contacts=enabled; +} + +void sal_enable_test_features(Sal*ctx, bool_t enabled){ + ctx->enable_test_features=enabled; +} + +SalResolverContext * sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data){ + return (SalResolverContext*)belle_sip_stack_resolve_a(sal->stack,name,port,family,(belle_sip_resolver_callback_t)cb,data); +} + +/* +void sal_resolve_cancel(Sal *sal, SalResolverContext* ctx){ + belle_sip_stack_resolve_cancel(sal->stack,ctx); +} +*/ + +void sal_enable_unconditional_answer(Sal *sal,int value) { + belle_sip_provider_enable_unconditional_answer(sal->prov,value); +} + +/** Parse a file containing either a certificate chain order in PEM format or a single DER cert + * @param auth_info structure where to store the result of parsing + * @param path path to certificate chain file + * @param format either PEM or DER + */ +void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path, SalCertificateRawFormat format) { + auth_info->certificates = (SalCertificatesChain*) belle_sip_certificates_chain_parse_file(path, (belle_sip_certificate_raw_format_t)format); // + if (auth_info->certificates) belle_sip_object_ref((belle_sip_object_t *) auth_info->certificates); +} + +/** + * Parse a file containing either a private or public rsa key + * @param auth_info structure where to store the result of parsing + * @param passwd password (optionnal) + */ +void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd) { + auth_info->key = (SalSigningKey *) belle_sip_signing_key_parse_file(path, passwd); + if (auth_info->key) belle_sip_object_ref((belle_sip_object_t *) auth_info->key); +} + +unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ + return belle_sip_random_bytes(ret,size); +} + + + diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h new file mode 100644 index 000000000..4ae34095b --- /dev/null +++ b/coreapi/bellesip_sal/sal_impl.h @@ -0,0 +1,162 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef SAL_IMPL_H_ +#define SAL_IMPL_H_ + +#include "sal/sal.h" +#include "belle-sip/belle-sip.h" +#include "belle-sip/belle-sdp.h" + + + +struct Sal{ + SalCallbacks callbacks; + MSList *pending_auths;/*MSList of SalOp */ + belle_sip_stack_t* stack; + belle_sip_provider_t *prov; + belle_sip_header_user_agent_t* user_agent; + belle_sip_listener_t *listener; + void *up; /*user pointer*/ + int session_expires; + unsigned int keep_alive; + char *root_ca; + char *uuid; + int refresher_retry_after; /*retry after value for refresher*/ + bool_t one_matching_codec; + bool_t use_tcp_tls_keep_alive; + bool_t nat_helper_enabled; + bool_t tls_verify; + bool_t tls_verify_cn; + bool_t use_dates; + bool_t auto_contacts; + bool_t enable_test_features; +}; + +typedef enum SalOpState { + SalOpStateEarly=0 + ,SalOpStateActive + ,SalOpStateTerminating /*this state is used to wait until a proceeding state, so we can send the cancel*/ + ,SalOpStateTerminated +}SalOpState; + +const char* sal_op_state_to_string(SalOpState value); + +typedef enum SalOpDir { + SalOpDirIncoming=0 + ,SalOpDirOutgoing +}SalOpDir; +typedef enum SalOpType { + SalOpUnknown, + SalOpRegister, + SalOpCall, + SalOpMessage, + SalOpPresence, + SalOpPublish, + SalOpSubscribe +}SalOpType; + +const char* sal_op_type_to_string(SalOpType type); + +struct SalOp{ + SalOpBase base; + belle_sip_listener_callbacks_t callbacks; + belle_sip_client_transaction_t *pending_auth_transaction; + belle_sip_server_transaction_t* pending_server_trans; + belle_sip_client_transaction_t* pending_client_trans; + SalAuthInfo* auth_info; + belle_sip_dialog_t* dialog; + belle_sip_header_replaces_t *replaces; + belle_sip_header_referred_by_t *referred_by; + SalMediaDescription *result; + belle_sdp_session_description_t *sdp_answer; + bool_t supports_session_timers; + SalOpState state; + SalOpDir dir; + belle_sip_refresher_t* refresher; + int ref; + SalOpType type; + SalPrivacyMask privacy; + belle_sip_header_t *event; /*used by SalOpSubscribe kinds*/ + bool_t auto_answer_asked; + bool_t sdp_offering; + bool_t call_released; + bool_t manual_refresher; +}; + + +belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *sal); +int sdp_to_media_description(belle_sdp_session_description_t *sdp, SalMediaDescription *desc); +belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method); + + +void sal_op_call_fill_cbs(SalOp*op); +void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog); + +/*return reffed op*/ +SalOp* sal_op_ref(SalOp* op); +/*return null, destroy op if ref count =0*/ +void* sal_op_unref(SalOp* op); +void sal_op_release_impl(SalOp *op); + +void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message); +int sal_op_send_request(SalOp* op, belle_sip_request_t* request); +int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires); +void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); +int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ); +belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_request_t *req, int code); + +/* + * return true if both from and to uri are sips + * */ +bool_t sal_op_is_secure(const SalOp* op); + +void sal_process_authentication(SalOp *op); +belle_sip_header_contact_t* sal_op_create_contact(SalOp *op) ; + +bool_t sal_compute_sal_errors(belle_sip_response_t* response,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) ; +/*presence*/ +void sal_op_presence_fill_cbs(SalOp*op); +/*messaging*/ +void sal_op_message_fill_cbs(SalOp*op); + +void sal_op_subscribe_fill_cbs(SalOp*op); + +/*call transfer*/ +void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t *tr); +void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t *tr); +/*create SalAuthInfo by copying username and realm from suth event*/ +SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) ; +void sal_add_pending_auth(Sal *sal, SalOp *op); +void sal_remove_pending_auth(Sal *sal, SalOp *op); +void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceModel *presence); + +belle_sip_response_t *sal_create_response_from_request(Sal *sal, belle_sip_request_t *req, int code); + +void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming); + +void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body); +bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody); + +SalReason sal_reason_to_sip_code(SalReason r); + +belle_sip_header_t * sal_make_supported_header(Sal *sal); + +#endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c new file mode 100644 index 000000000..a286001b2 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -0,0 +1,813 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" +#include "offeranswer.h" + +/*used for calls terminated before creation of a dialog*/ +static void call_set_released(SalOp* op){ + if (!op->call_released){ + op->state=SalOpStateTerminated; + op->base.root->callbacks.call_released(op); + op->call_released=TRUE; + } +} + +/*used when the SalOp was ref'd by the dialog, in which case we rely only on the dialog terminated notification*/ +static void call_set_released_and_unref(SalOp* op) { + call_set_released(op); + sal_op_unref(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); + } +} + +static void sdp_process(SalOp *h){ + ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); + if (h->result){ + sal_media_description_unref(h->result); + } + h->result=sal_media_description_new(); + if (h->sdp_offering){ + offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result); + }else{ + int i; + if (h->sdp_answer){ + belle_sip_object_unref(h->sdp_answer); + } + offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec); + h->sdp_answer=(belle_sdp_session_description_t *)belle_sip_object_ref(media_description_to_sdp(h->result)); + /*once we have generated the SDP answer, we modify the result description for processing by the upper layer. + It should contains media parameters constraint from the remote offer, not our response*/ + strcpy(h->result->addr,h->base.remote_media->addr); + h->result->bandwidth=h->base.remote_media->bandwidth; + + for(i=0;iresult->n_active_streams;++i){ + strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); + h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; + h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; + h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; + strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); + h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; + + if (h->result->streams[i].proto == SalProtoRtpSavp) { + h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; + } + } + } + +} +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; + belle_sip_error_code error = BELLE_SIP_OK; + size_t length = 0; + char buff[2048]; + + if (session_desc) { + content_type = belle_sip_header_content_type_create("application","sdp"); + error = belle_sip_object_marshal(BELLE_SIP_OBJECT(session_desc),buff,sizeof(buff),&length); + if (error != BELLE_SIP_OK) { + ms_error("Buffer too small or sdp too big"); + return -1; + } + + content_length= belle_sip_header_content_length_create(length); + belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_type)); + belle_sip_message_add_header(msg,BELLE_SIP_HEADER(content_length)); + belle_sip_message_set_body(msg,buff,length); + return 0; + } else { + return -1; + } +} +static int set_sdp_from_desc(belle_sip_message_t *msg, const SalMediaDescription *desc){ + int err; + belle_sdp_session_description_t *sdp=media_description_to_sdp(desc); + err=set_sdp(msg,sdp); + belle_sip_object_unref(sdp); + return err; + +} +static void call_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + SalOp* op=(SalOp*)user_ctx; + + if (op->state==SalOpStateTerminated) return; + + if (!op->dialog) { + /*call terminated very early*/ + op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Service Unavailable",503); + call_set_released(op); + } else { + /*dialog will terminated shortly, nothing to do*/ + } +} +static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { + SalOp* op=(SalOp*)ctx; + + if (op->dialog && op->dialog==belle_sip_dialog_terminated_event_get_dialog(event)) { + /*belle_sip_transaction_t* trans=belle_sip_dialog_get_last_transaction(op->dialog);*/ + ms_message("Dialog [%p] terminated for op [%p]",belle_sip_dialog_terminated_event_get_dialog(event),op); + + switch(belle_sip_dialog_get_previous_state(op->dialog)) { + case BELLE_SIP_DIALOG_CONFIRMED: + if (op->state!=SalOpStateTerminated && op->state!=SalOpStateTerminating) { + /*this is probably a normal termination from a BYE*/ + op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); + op->state=SalOpStateTerminating; + } + break; + default: + break; + } + belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) + ,(belle_sip_callback_t) call_set_released_and_unref + , op); + } else { + ms_error("dialog unknown for op "); + } +} + +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); + } +} + +static void cancelling_invite(SalOp* op ){ + belle_sip_request_t* cancel; + ms_message("Cancelling INVITE request from [%s] to [%s] ",sal_op_get_from(op), sal_op_get_to(op)); + cancel = belle_sip_client_transaction_create_cancel(op->pending_client_trans); + sal_op_send_request(op,cancel); + op->state=SalOpStateTerminating; +} + +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; + belle_sip_dialog_state_t dialog_state; + belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(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); + + + if (!client_transaction) { + ms_warning("Discarding stateless response [%i] on op [%p]",code,op); + return; + } + req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + set_or_update_dialog(op,belle_sip_response_event_get_dialog(event)); + dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; + + ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,op->dialog,belle_sip_dialog_state_to_string(dialog_state)); + + switch(dialog_state) { + case BELLE_SIP_DIALOG_NULL: + case BELLE_SIP_DIALOG_EARLY: { + if (strcmp("INVITE",belle_sip_request_get_method(req))==0 ) { + if (op->state == SalOpStateTerminating) { + /*check if CANCEL was sent before*/ + if (strcmp("CANCEL",belle_sip_request_get_method(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_client_trans))))!=0) { + /*it wasn't sent */ + if (code<200) { + cancelling_invite(op); + }else{ + /* no need to send the INVITE because the UAS rejected the INVITE*/ + if (op->dialog==NULL) call_set_released(op); + } + } else { + /*it was sent already, so just expect the 487 or any error response to send the call_released() notification*/ + if (code>=300){ + if (op->dialog==NULL) call_set_released(op); + } + } + } else if (code >= 180 && code<300) { + handle_sdp_from_response(op,response); + op->base.root->callbacks.call_ringing(op); + } else if (code>=300){ + call_set_error(op,response); + if (op->dialog==NULL) call_set_released(op); + } + } + } + break; + case BELLE_SIP_DIALOG_CONFIRMED: { + switch (op->state) { + case SalOpStateEarly:/*invite case*/ + case SalOpStateActive: /*re-invite case*/ + if (code >=200 + && code<300 + && strcmp("INVITE",belle_sip_request_get_method(req))==0) { + handle_sdp_from_response(op,response); + ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); + if (ack==NULL) { + ms_error("This call has been already terminated."); + return ; + } + if (op->sdp_answer){ + set_sdp(BELLE_SIP_MESSAGE(ack),op->sdp_answer); + belle_sip_object_unref(op->sdp_answer); + op->sdp_answer=NULL; + } + belle_sip_dialog_send_ack(op->dialog,ack); + op->base.root->callbacks.call_accepted(op); /*INVITE*/ + op->state=SalOpStateActive; + } else if (code >= 300 && strcmp("INVITE",belle_sip_request_get_method(req))==0){ + call_set_error(op,response); + } else { + /*ignoring*/ + } + break; + case SalOpStateTerminating: + sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); + break; + case SalOpStateTerminated: + default: + ms_error("Call op [%p] receives unexpected answer [%i] while in state [%s].",op,code, sal_op_state_to_string(op->state)); + } + } + break; + case BELLE_SIP_DIALOG_TERMINATED: { + if (code >= 300){ + call_set_error(op,response); + } + } + break; + default: { + ms_error("call op [%p] receive answer [%i] not implemented",op,code); + } + break; + } +} + +static void call_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + SalOp* op=(SalOp*)user_ctx; + + if (op->state==SalOpStateTerminated) return; + + if (!op->dialog) { + /*call terminated very early*/ + op->base.root->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,"Request Timeout",408); + call_set_released(op); + } else { + /*dialog will terminated shortly, nothing to do*/ + } +} + +static void call_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + SalOp* op = (SalOp*)user_ctx; + belle_sip_client_transaction_t *client_transaction=belle_sip_transaction_terminated_event_get_client_transaction(event); + belle_sip_server_transaction_t *server_transaction=belle_sip_transaction_terminated_event_get_server_transaction(event); + belle_sip_request_t* req; + belle_sip_response_t* resp; + if (client_transaction) { + req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(client_transaction)); + } else { + req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); + resp=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(server_transaction)); + } + if (op->state ==SalOpStateTerminating + && strcmp("BYE",belle_sip_request_get_method(req))==0 + && (!resp || (belle_sip_response_get_status_code(resp) !=401 + && belle_sip_response_get_status_code(resp) !=407))) { + if (op->dialog==NULL) call_set_released(op); + } +} + +static void call_terminated(SalOp* op,belle_sip_server_transaction_t* server_transaction, belle_sip_request_t* request,int status_code) { + belle_sip_response_t* resp; + op->base.root->callbacks.call_terminated(op,op->dir==SalOpDirIncoming?sal_op_get_from(op):sal_op_get_to(op)); + resp=sal_op_create_response_from_request(op,request,status_code); + belle_sip_server_transaction_send_response(server_transaction,resp); +} + +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); + 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; +} + +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; + belle_sdp_session_description_t* sdp; + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_dialog_state_t dialog_state; + belle_sip_response_t* resp; + belle_sip_header_t* call_info; + + if (strcmp("ACK",belle_sip_request_get_method(req))!=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 (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 (!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)); + } + 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 (!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) { + ms_warning("replace header already set"); + } + + 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) { + 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(belle_sip_request_event_get_server_transaction(event)) { + /*first answer 200 ok to cancel*/ + belle_sip_server_transaction_send_response(server_transaction + ,sal_op_create_response_from_request(op,req,200)); + /*terminate invite transaction*/ + call_terminated(op + ,op->pending_server_trans + ,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),487); + + + } else { + /*call leg does not exist*/ + 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) { + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } 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); + } + break; + } + case BELLE_SIP_DIALOG_CONFIRMED: + /*great ACK received*/ + if (strcmp("ACK",belle_sip_request_get_method(req))==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); + } + } + /*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) { + 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) { + /*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){ + 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*/ + ms_message("Receiving VFU request on op [%p]",op); + if (op->base.root->callbacks.vfu_request){ + op->base.root->callbacks.vfu_request(op); + + } + }else{ + SalBody salbody; + if (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) { + if (sal_body_has_type(&salbody,"application","dtmf-relay")){ + char tmp[10]; + if (sal_lines_get_value(salbody.data, "Signal",tmp, sizeof(tmp))){ + op->base.root->callbacks.dtmf_received(op,tmp[0]); + } + }else + op->base.root->callbacks.info_received(op,&salbody); + } else { + op->base.root->callbacks.info_received(op,NULL); + } + } + 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) { + sal_op_process_refer(op,event,server_transaction); + } else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { + sal_op_call_process_notify(op,event,server_transaction); + } else if (strcmp("OPTIONS",belle_sip_request_get_method(req))==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) { + /*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{ + ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); + unsupported_method(server_transaction,req); + } + break; + default: + ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + break; + } + + if (server_transaction) belle_sip_object_unref(server_transaction); + +} + + +/*Call API*/ +int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ + if (desc) + sal_media_description_ref(desc); + if (op->base.local_media) + sal_media_description_unref(op->base.local_media); + op->base.local_media=desc; + + if (op->base.remote_media){ + /*case of an incoming call where we modify the local capabilities between the time + * the call is ringing and it is accepted (for example if you want to accept without video*/ + /*reset the sdp answer so that it is computed again*/ + if (op->sdp_answer){ + belle_sip_object_unref(op->sdp_answer); + op->sdp_answer=NULL; + } + } + return 0; +} + +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"); + return header_allow; +} + +static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow())); + + if (op->base.root->session_expires!=0){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "200")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer")); + } + if (op->base.local_media){ + op->sdp_offering=TRUE; + set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),op->base.local_media); + }else op->sdp_offering=FALSE; + return; +} + +int sal_call(SalOp *op, const char *from, const char *to){ + belle_sip_request_t* invite; + op->dir=SalOpDirOutgoing; + + sal_op_set_from(op,from); + sal_op_set_to(op,to); + + ms_message("[%s] calling [%s] on op [%p]", from, to, op); + invite=sal_op_build_request(op,"INVITE"); + + sal_op_fill_invite(op,invite); + + sal_op_call_fill_cbs(op); + if (op->replaces){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->replaces)); + } + if (op->referred_by) + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(op->referred_by)); + + return sal_op_send_request(op,invite); +} + +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; + op->type=SalOpCall; +} + +static void handle_offer_answer_response(SalOp* op, belle_sip_response_t* response) { + if (op->base.local_media){ + /*this is the case where we received an invite without SDP*/ + if (op->sdp_offering) { + set_sdp_from_desc(BELLE_SIP_MESSAGE(response),op->base.local_media); + }else{ + + if (op->sdp_answer==NULL) + sdp_process(op); + + if (op->sdp_answer){ + set_sdp(BELLE_SIP_MESSAGE(response),op->sdp_answer); + belle_sip_object_unref(op->sdp_answer); + op->sdp_answer=NULL; + } + } + }else{ + ms_error("You are accepting a call but not defined any media capabilities !"); + } +} + +int sal_call_notify_ringing(SalOp *op, bool_t early_media){ + int status_code =early_media?183:180; + belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); + belle_sip_response_t* ringing_response = sal_op_create_response_from_request(op,req,status_code); + belle_sip_header_t *require; + const char *tags=NULL; + + if (early_media){ + handle_offer_answer_response(op,ringing_response); + } + require=belle_sip_message_get_header((belle_sip_message_t*)req,"Require"); + 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"))); + } + +#ifndef SAL_OP_CALL_FORCE_CONTACT_IN_RINGING + if (tags && strstr(tags,"100rel")!=0) +#endif + { + belle_sip_header_address_t* contact= (belle_sip_header_address_t*)sal_op_get_contact_address(op); + belle_sip_header_contact_t* contact_header; + if (contact && (contact_header=belle_sip_header_contact_create(contact))) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(ringing_response),BELLE_SIP_HEADER(contact_header)); + } + } + belle_sip_server_transaction_send_response(op->pending_server_trans,ringing_response); + return 0; +} + + +/*accept an incoming call or, during a call accept a reINVITE*/ +int sal_call_accept(SalOp*h){ + belle_sip_response_t *response; + belle_sip_header_contact_t* contact_header; + + if (!h->pending_server_trans) { + ms_error("No transaction to accept for op [%p]",h); + return -1; + } + + /* 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); + + if (response==NULL){ + ms_error("Fail to build answer for call"); + return -1; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow())); + if (h->base.root->session_expires!=0){ + if (h->supports_session_timers) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create("Supported", "timer")); + } + } + + if ((contact_header=sal_op_create_contact(h))) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact_header)); + } + + handle_offer_answer_response(h,response); + + belle_sip_server_transaction_send_response(h->pending_server_trans,response); + return 0; +} + +int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*optional*/){ + belle_sip_response_t* response; + belle_sip_header_contact_t* contact=NULL; + int status=sal_reason_to_sip_code(reason); + + if (reason==SalReasonRedirect){ + if (redirection!=NULL) { + if (strstr(redirection,"sip:")!=0) status=302; + 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 { + ms_error("Cannot redirect to null"); + } + } + response = sal_op_create_response_from_request(op,belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)),status); + if (contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(contact)); + belle_sip_server_transaction_send_response(op->pending_server_trans,response); + return 0; +} + +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); + } + return -1; +} + +SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ + return h->base.remote_media;; +} + +SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ + if (h->base.local_media && h->base.remote_media && !h->result){ + sdp_process(h); + } + return h->result; +} + +int sal_call_send_dtmf(SalOp *h, char dtmf){ + if (h->dialog && (belle_sip_dialog_get_state(h->dialog) == BELLE_SIP_DIALOG_CONFIRMED || belle_sip_dialog_get_state(h->dialog) == BELLE_SIP_DIALOG_EARLY)){ + belle_sip_request_t *req=belle_sip_dialog_create_queued_request(h->dialog,"INFO"); + if (req){ + int bodylen; + char dtmf_body[128]={0}; + + snprintf(dtmf_body, sizeof(dtmf_body)-1, "Signal=%c\r\nDuration=250\r\n", dtmf); + bodylen=strlen(dtmf_body); + belle_sip_message_set_body((belle_sip_message_t*)req,dtmf_body,bodylen); + belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_length_create(bodylen)); + belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_type_create("application", "dtmf-relay")); + sal_op_send_request(h,req); + }else ms_error("sal_call_send_dtmf(): could not build request"); + }else ms_error("sal_call_send_dtmf(): no dialog"); + return 0; +} + +int sal_call_terminate(SalOp *op){ + belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; + if (op->state==SalOpStateTerminating || op->state==SalOpStateTerminated) { + ms_error("Cannot terminate op [%p] in state [%s]",op,sal_op_state_to_string(op->state)); + return -1; + } + switch(dialog_state) { + case BELLE_SIP_DIALOG_CONFIRMED: { + sal_op_send_request(op,belle_sip_dialog_create_request(op->dialog,"BYE")); + op->state=SalOpStateTerminating; + break; + } + case BELLE_SIP_DIALOG_NULL: { + if (op->dir == SalOpDirIncoming) { + sal_call_decline(op, SalReasonDeclined,NULL); + op->state=SalOpStateTerminated; + } else if (op->pending_client_trans){ + if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(op->pending_client_trans)) == BELLE_SIP_TRANSACTION_PROCEEDING){ + cancelling_invite(op); + }else{ + /* Case where the CANCEL cannot be sent because no provisional response was received so far. + * The Op must be kept for the time of the transaction in case a response is received later. + * The state is passed to Terminating to remember to terminate later. + */ + op->state=SalOpStateTerminating; + } + } + break; + } + case BELLE_SIP_DIALOG_EARLY: { + if (op->dir == SalOpDirIncoming) { + sal_call_decline(op, SalReasonDeclined,NULL); + op->state=SalOpStateTerminated; + } else { + cancelling_invite(op); + } + break; + } + default: { + ms_error("sal_call_terminate not implemented yet for dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + return -1; + } + } + return 0; +} + +bool_t sal_call_autoanswer_asked(SalOp *op){ + return op->auto_answer_asked; +} + +void sal_call_send_vfu_request(SalOp *op){ + char info_body[] = + "" + "" + " " + " " + " " + " " + " " + ""; + size_t content_lenth = sizeof(info_body) - 1; + belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; /*no dialog = dialog in NULL state*/ + if (dialog_state == BELLE_SIP_DIALOG_CONFIRMED) { + belle_sip_request_t* info = belle_sip_dialog_create_queued_request(op->dialog,"INFO"); + int error=TRUE; + if (info) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","media_control+xml"))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_lenth))); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(info),info_body,content_lenth); + error=sal_op_send_request(op,info); + } + if (error) + ms_warning("Cannot send vfu request to [%s] ", sal_op_get_to(op)); + + } else { + ms_warning("Cannot send vfu request to [%s] because dialog [%p] in wrong state [%s]",sal_op_get_to(op) + ,op->dialog + ,belle_sip_dialog_state_to_string(dialog_state)); + } + + return ; +} + +int sal_call_is_offerer(const SalOp *h){ + return h->sdp_offering; +} + + + + diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c new file mode 100644 index 000000000..0fad03e83 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -0,0 +1,254 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" +#include "offeranswer.h" + + + +/*call transfer*/ +static void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces) { + if (op->replaces){ + belle_sip_object_unref(op->replaces); + } + op->replaces=replaces; + belle_sip_object_ref(op->replaces); +} +static void sal_op_set_referred_by(SalOp* op,belle_sip_header_referred_by_t* referred_by) { + if (op->referred_by){ + belle_sip_object_unref(op->referred_by); + } + op->referred_by=referred_by; + belle_sip_object_ref(op->referred_by); +} + + +int sal_call_refer_to(SalOp *op, belle_sip_header_refer_to_t* refer_to, belle_sip_header_referred_by_t* referred_by){ + char* tmp; + belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):NULL; /*cannot create request if dialog not set yet*/ + if (!req) { + tmp=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to))); + ms_error("Cannot refer to [%s] for op [%p]",tmp,op); + belle_sip_free(tmp); + return -1; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to)); + if (referred_by) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(referred_by)); + return sal_op_send_request(op,req); +} + +int sal_call_refer(SalOp *op, const char *refer_to){ + belle_sip_header_address_t *referred_by; + belle_sip_header_refer_to_t* refer_to_header; + if (op->dialog) { + referred_by=(belle_sip_header_address_t*)belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_dialog_get_local_party(op->dialog))); + }else{ + referred_by=BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)); + } + refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); + + return sal_call_refer_to(op,refer_to_header,belle_sip_header_referred_by_create(referred_by)); +} + +int sal_call_refer_with_replaces(SalOp *op, SalOp *other_call_op){ + belle_sip_dialog_state_t other_call_dialog_state=other_call_op->dialog?belle_sip_dialog_get_state(other_call_op->dialog):BELLE_SIP_DIALOG_NULL; + belle_sip_dialog_state_t op_dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; + belle_sip_header_replaces_t* replaces; + belle_sip_header_refer_to_t* refer_to; + belle_sip_header_referred_by_t* referred_by; + const char* from_tag; + const char* to_tag; + char* escaped_replaces; + /*first, build refer to*/ + if (other_call_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) { + ms_error(" wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED",belle_sip_dialog_state_to_string(other_call_dialog_state) + ,other_call_op); + return -1; + } + if (op_dialog_state!=BELLE_SIP_DIALOG_CONFIRMED) { + ms_error(" wrong dialog state [%s] for op [%p], should be BELLE_SIP_DIALOG_CONFIRMED",belle_sip_dialog_state_to_string(op_dialog_state) + ,op); + return -1; + } + + refer_to=belle_sip_header_refer_to_create(belle_sip_dialog_get_remote_party(other_call_op->dialog)); + belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(refer_to)); + if (belle_sip_dialog_is_server(other_call_op->dialog)) { + to_tag=belle_sip_dialog_get_local_tag(other_call_op->dialog); + from_tag=belle_sip_dialog_get_remote_tag(other_call_op->dialog);; + + } else { + from_tag=belle_sip_dialog_get_local_tag(other_call_op->dialog); + to_tag=belle_sip_dialog_get_remote_tag(other_call_op->dialog);; + } + replaces=belle_sip_header_replaces_create(belle_sip_header_call_id_get_call_id(belle_sip_dialog_get_call_id(other_call_op->dialog)) + ,from_tag,to_tag); + escaped_replaces=belle_sip_header_replaces_value_to_escaped_string(replaces); + belle_sip_uri_set_header(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)),"Replaces",escaped_replaces); + belle_sip_free(escaped_replaces); + referred_by=belle_sip_header_referred_by_create(belle_sip_dialog_get_local_party(op->dialog)); + belle_sip_parameters_clean(BELLE_SIP_PARAMETERS(referred_by)); + return sal_call_refer_to(op,refer_to,referred_by); +} +/* +int sal_call_accept_refer(SalOp *h){ + ms_fatal("sal_call_accept_refer not implemented yet"); + return -1; +}*/ +/*informs this call is consecutive to an incoming refer */ +int sal_call_set_referer(SalOp *h, SalOp *refered_call){ + if (refered_call->replaces) + sal_op_set_replaces(h,refered_call->replaces); + if (refered_call->referred_by) + sal_op_set_referred_by(h,refered_call->referred_by); + return 0; +} +/* returns the SalOp of a call that should be replaced by h, if any */ +SalOp *sal_call_get_replaces(SalOp *op){ + if (op && op->replaces){ + belle_sip_dialog_t* dialog=belle_sip_provider_find_dialog(op->base.root->prov + ,belle_sip_header_replaces_get_call_id(op->replaces) + ,belle_sip_header_replaces_get_from_tag(op->replaces) + ,belle_sip_header_replaces_get_to_tag(op->replaces)); + + if (dialog) { + return (SalOp*)belle_sip_dialog_get_application_data(dialog); + } + } + return NULL; +} + +static int send_notify_for_refer(SalOp* op, int code, const char *reason){ + belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"); + char *sipfrag=belle_sip_strdup_printf("SIP/2.0 %i %s\r\n",code,reason); + size_t content_length=strlen(sipfrag); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,-1))); + + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),belle_sip_header_create("Event","refer")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_type_create("message","sipfrag"))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); + belle_sip_message_assign_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length); + return sal_op_send_request(op,notify); +} + +static void notify_last_response(SalOp *op, SalOp *newcall){ + belle_sip_client_transaction_t *tr=newcall->pending_client_trans; + belle_sip_response_t *resp=NULL; + if (tr){ + resp=belle_sip_transaction_get_response((belle_sip_transaction_t*)tr); + } + if (resp==NULL){ + send_notify_for_refer(op, 100, "Trying"); + }else{ + send_notify_for_refer(op, belle_sip_response_get_status_code(resp), belle_sip_response_get_reason_phrase(resp)); + } +} + +int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ + belle_sip_dialog_state_t state; + if(belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_TERMINATED){ + return 0; + } + state = newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL; + switch(state) { + case BELLE_SIP_DIALOG_EARLY: + send_notify_for_refer(op, 100, "Trying"); + break; + case BELLE_SIP_DIALOG_CONFIRMED: + send_notify_for_refer(op, 200, "Ok"); + break; + case BELLE_SIP_DIALOG_TERMINATED: + case BELLE_SIP_DIALOG_NULL: + notify_last_response(op,newcall); + break; + } + return 0; +} + + +void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t *server_transaction){ + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_header_refer_to_t *refer_to= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_refer_to_t); + belle_sip_header_referred_by_t *referred_by= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_referred_by_t); + belle_sip_response_t* resp; + belle_sip_uri_t* refer_to_uri; + char* refer_to_uri_str; + + ms_message("Receiving REFER request on op [%p]",op); + if (refer_to) { + refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)); + + if (refer_to_uri && belle_sip_uri_get_header(refer_to_uri,"Replaces")) { + sal_op_set_replaces(op,belle_sip_header_replaces_create2(belle_sip_uri_get_header(refer_to_uri,"Replaces"))); + belle_sip_uri_remove_header(refer_to_uri,"Replaces"); + } + if (referred_by){ + sal_op_set_referred_by(op,referred_by); + } + refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); + resp = sal_op_create_response_from_request(op,req,202); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->base.root->callbacks.refer_received(op->base.root,op,refer_to_uri_str); + belle_sip_free(refer_to_uri_str); + } else { + ms_warning("cannot do anything with the refer without destination\n"); + resp = sal_op_create_response_from_request(op,req,501); + belle_sip_server_transaction_send_response(server_transaction,resp); + } + +} + +void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event, belle_sip_server_transaction_t* server_transaction){ + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + belle_sip_header_t* header_event=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"); + belle_sip_header_content_type_t* content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t); + belle_sip_response_t* resp; + + ms_message("Receiving NOTIFY request on op [%p]",op); + if (header_event + && strncasecmp(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(header_event)),"refer",strlen("refer"))==0 + && content_type + && strcmp(belle_sip_header_content_type_get_type(content_type),"message")==0 + && strcmp(belle_sip_header_content_type_get_subtype(content_type),"sipfrag")==0 + && body){ + belle_sip_response_t* sipfrag=BELLE_SIP_RESPONSE(belle_sip_message_parse(body)); + + if (sipfrag){ + int code=belle_sip_response_get_status_code(sipfrag); + SalReferStatus status=SalReferFailed; + if (code==100){ + status=SalReferTrying; + }else if (code==200){ + status=SalReferSuccess; + }else if (code>=400){ + status=SalReferFailed; + } + belle_sip_object_unref(sipfrag); + resp = sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->base.root->callbacks.notify_refer(op,status); + } + }else{ + ms_error("Notify without sipfrag, trashing"); + resp = sal_op_create_response_from_request(op,req,501); + belle_sip_server_transaction_send_response(server_transaction,resp); + } +} + diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c new file mode 100644 index 000000000..376a88bcd --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -0,0 +1,268 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" + +SalSubscribeStatus get_subscription_state(belle_sip_message_t *msg){ + belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(msg,belle_sip_header_subscription_state_t); + SalSubscribeStatus sss=SalSubscribeNone; + if (subscription_state_header){ + if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED)==0) + sss=SalSubscribeTerminated; + else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_PENDING)==0) + sss=SalSubscribePending; + else if (strcmp(belle_sip_header_subscription_state_get_state(subscription_state_header),BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE)==0) + sss=SalSubscribeActive; + } + return sss; +} + +static void subscribe_refresher_listener (belle_sip_refresher_t* refresher + ,void* user_pointer + ,unsigned int status_code + ,const char* reason_phrase) { + 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; + + ms_message("Subscribe refresher [%i] reason [%s] ",status_code,reason_phrase?reason_phrase:"none"); + if (status_code>=200 && status_code<300){ + if (status_code==200) sss=SalSubscribeActive; + else if (status_code==202) sss=SalSubscribePending; + set_or_update_dialog(op,belle_sip_transaction_get_dialog(tr)); + } + if (status_code>=200){ + sal_compute_sal_errors_from_code(status_code,&error,&sr); + op->base.root->callbacks.subscribe_response(op,sss,error,sr); + } + +} + +static void subscribe_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + ms_error("subscribe_process_io_error not implemented yet"); +} + +static void subscribe_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { + SalOp* op= (SalOp*)ctx; + if (op->dialog) { + op->dialog=NULL; + sal_op_unref(op); + } +} + +static void subscribe_response_event(void *op_base, const belle_sip_response_event_t *event){ +} + +static void subscribe_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { +} + +static void subscribe_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { +} + +static void handle_notify(SalOp *op, belle_sip_request_t *req, const char *eventname, SalBody * body){ + SalSubscribeStatus sub_state; + belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); + belle_sip_response_t* resp; + belle_sip_server_transaction_t* server_transaction = op->pending_server_trans; + + if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { + sub_state=SalSubscribeTerminated; + ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); + } else + sub_state=SalSubscribeActive; + sal_op_ref(op); + op->base.root->callbacks.notify(op,sub_state,eventname,body); + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + sal_op_unref(op); +} + +static void subscribe_process_request_event(void *op_base, const belle_sip_request_event_t *event) { + SalOp* op = (SalOp*)op_base; + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_dialog_state_t dialog_state; + belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); + belle_sip_header_t *event_header; + SalBody body; + belle_sip_response_t* resp; + const char *eventname=NULL; + const char *method=belle_sip_request_get_method(req); + + belle_sip_object_ref(server_transaction); + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + op->pending_server_trans=server_transaction; + + event_header=belle_sip_message_get_header((belle_sip_message_t*)req,"Event"); + sal_op_get_body(op,(belle_sip_message_t*)req,&body); + + if (event_header==NULL){ + ms_warning("No event header in incoming SUBSCRIBE."); + resp=sal_op_create_response_from_request(op,req,400); + belle_sip_server_transaction_send_response(server_transaction,resp); + return; + } + if (op->event==NULL) { + op->event=event_header; + belle_sip_object_ref(op->event); + } + eventname=belle_sip_header_get_unparsed_value(event_header); + + if (!op->dialog) { + if (strcmp(method,"SUBSCRIBE")==0){ + op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction)); + belle_sip_dialog_set_application_data(op->dialog,op); + sal_op_ref(op); + ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op)); + }else{ /*this is a NOTIFY*/ + handle_notify(op,req,eventname,&body); + return; + } + } + dialog_state=belle_sip_dialog_get_state(op->dialog); + switch(dialog_state) { + + case BELLE_SIP_DIALOG_NULL: { + op->base.root->callbacks.subscribe_received(op,eventname,body.type ? &body : NULL); + break; + } + case BELLE_SIP_DIALOG_EARLY: + ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",belle_sip_request_get_method(req),op->dialog); + break; + + case BELLE_SIP_DIALOG_CONFIRMED: + if (strcmp("NOTIFY",method)==0) { + handle_notify(op,req,eventname,&body); + } else if (strcmp("SUBSCRIBE",method)==0) { + /*either a refresh of an unsubscribe*/ + if (expires && belle_sip_header_expires_get_expires(expires)>0) { + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } else if(expires) { + ms_message("Unsubscribe received from [%s]",sal_op_get_from(op)); + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->base.root->callbacks.subscribe_closed(op); + } + } + break; + default: { + ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + } + } +} + +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; + op->type=SalOpSubscribe; +} + + +int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){ + belle_sip_request_t *req=NULL; + + if (from) + sal_op_set_from(op,from); + if (to) + sal_op_set_to(op,to); + + if (!op->dialog){ + sal_op_subscribe_fill_cbs(op); + /*???sal_exosip_fix_route(op); make sure to ha ;lr*/ + req=sal_op_build_request(op,"SUBSCRIBE"); + if (eventname){ + if (op->event) belle_sip_object_unref(op->event); + op->event=belle_sip_header_create("Event",eventname); + belle_sip_object_ref(op->event); + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires))); + sal_op_add_body(op,(belle_sip_message_t*)req,body); + return sal_op_send_and_create_refresher(op,req,expires,subscribe_refresher_listener); + }else if (op->refresher){ + const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); + /* modify last request to update body*/ + sal_op_add_body(op,(belle_sip_message_t*)last_req,body); + return belle_sip_refresher_refresh(op->refresher,expires); + } + ms_warning("sal_subscribe(): no dialog and no refresher ?"); + return -1; +} + +int sal_unsubscribe(SalOp *op){ + if (op->refresher){ + const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr); + sal_op_add_body(op,(belle_sip_message_t*)last_req,NULL); + belle_sip_refresher_refresh(op->refresher,0); + return 0; + } + return -1; +} + +int sal_subscribe_accept(SalOp *op){ + belle_sip_request_t* req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)); + belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); + belle_sip_response_t* resp = sal_op_create_response_from_request(op,req,200); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(expires)); + belle_sip_server_transaction_send_response(op->pending_server_trans,resp); + return 0; +} + +int sal_subscribe_decline(SalOp *op, SalReason reason){ + belle_sip_response_t* resp = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(op->pending_server_trans)), + sal_reason_to_sip_code(reason)); + belle_sip_server_transaction_send_response(op->pending_server_trans,resp); + return 0; +} + +int sal_notify(SalOp *op, const SalBody *body){ + belle_sip_request_t* notify; + + if (!op->dialog) return -1; + + if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1; + + if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),op->event); + + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600))); + + sal_op_add_body(op,(belle_sip_message_t*)notify, body); + return sal_op_send_request(op,notify); +} + +int sal_notify_close(SalOp *op){ + belle_sip_request_t* notify; + if (!op->dialog) return -1; + if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1; + if (op->event) belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),op->event); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); + return sal_op_send_request(op,notify); +} + diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c new file mode 100644 index 000000000..49fa7c5f8 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -0,0 +1,608 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" + + +/*create an operation */ +SalOp * sal_op_new(Sal *sal){ + SalOp *op=ms_new0(SalOp,1); + __sal_op_init(op,sal); + op->type=SalOpUnknown; + op->privacy=SalPrivacyNone; + op->manual_refresher=FALSE;/*tells that requests with expiry (SUBSCRIBE, PUBLISH) will be automatically refreshed*/ + sal_op_ref(op); + return op; +} + +void sal_op_release(SalOp *op){ + /*if in terminating state, keep this state because it means we are waiting for a response to be able to terminate the operation.*/ + if (op->state!=SalOpStateTerminating) + op->state=SalOpStateTerminated; + sal_op_set_user_pointer(op,NULL);/*mandatory because releasing op doesn't not mean freeing op. Make sure back pointer will not be used later*/ + if (op->refresher) { + belle_sip_refresher_stop(op->refresher); + } + sal_op_unref(op); +} + +void sal_op_release_impl(SalOp *op){ + ms_message("Destroying op [%p] of type [%s]",op,sal_op_type_to_string(op->type)); + if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction); + if (op->auth_info) { + sal_remove_pending_auth(op->base.root,op); + sal_auth_info_delete(op->auth_info); + } + if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); + if (op->refresher) { + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + } + if (op->result) + sal_media_description_unref(op->result); + if(op->replaces) belle_sip_object_unref(op->replaces); + if(op->referred_by) belle_sip_object_unref(op->referred_by); + + if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + if (op->event) belle_sip_object_unref(op->event); + __sal_op_free(op); + return ; +} + +void sal_op_authenticate(SalOp *op, const SalAuthInfo *info){ + if (op->type == SalOpRegister) { + /*Registration authenticate is just about registering again*/ + sal_register_refresh(op,-1); + }else { + /*for sure auth info will be accesible from the provider*/ + sal_process_authentication(op); + } + return ; +} + +void sal_op_cancel_authentication(SalOp *h){ + ms_fatal("sal_op_cancel_authentication not implemented yet"); + return ; +} + +SalAuthInfo * sal_op_get_auth_requested(SalOp *op){ + return op->auth_info; +} + +belle_sip_header_contact_t* sal_op_create_contact(SalOp *op){ + belle_sip_header_contact_t* contact_header; + belle_sip_uri_t* contact_uri; + if (sal_op_get_contact_address(op)) { + contact_header = belle_sip_header_contact_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_contact_address(op))); + } else { + contact_header= belle_sip_header_contact_new(); + } + if (!(contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact_header)))) { + /*no uri, just creating a new one*/ + contact_uri=belle_sip_uri_new(); + belle_sip_header_address_set_uri(BELLE_SIP_HEADER_ADDRESS(contact_header),contact_uri); + } + belle_sip_uri_set_secure(contact_uri,sal_op_is_secure(op)); + + belle_sip_header_contact_set_automatic(contact_header,op->base.root->auto_contacts); + if (op->base.root->uuid){ + if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance")==0){ + char *instance_id=belle_sip_strdup_printf("\"\"",op->base.root->uuid); + belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(contact_header),"+sip.instance",instance_id); + belle_sip_free(instance_id); + } + } + return contact_header; +} + +belle_sip_header_t * sal_make_supported_header(Sal *sal){ + return belle_sip_header_create("Supported","replaces, outbound"); +} + +belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method) { + belle_sip_header_from_t* from_header; + belle_sip_header_to_t* to_header; + belle_sip_provider_t* prov=op->base.root->prov; + belle_sip_request_t *req; + belle_sip_uri_t* req_uri; + char token[10]; + + + if (strcmp("REGISTER",method)==0 || op->privacy==SalPrivacyNone) { + from_header = belle_sip_header_from_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op)) + ,belle_sip_random_token(token,sizeof(token))); + } else { + from_header=belle_sip_header_from_create2("Anonymous ",belle_sip_random_token(token,sizeof(token))); + } + /*make sure to preserve components like headers or port*/ + req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)))); + belle_sip_uri_set_secure(req_uri,sal_op_is_secure(op)); + + to_header = belle_sip_header_to_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_to_address(op)),NULL); + + req=belle_sip_request_create( + req_uri, + method, + belle_sip_provider_create_call_id(prov), + belle_sip_header_cseq_create(20,method), + from_header, + to_header, + belle_sip_header_via_new(), + 70); + + if (op->privacy & SalPrivacyId) { + belle_sip_header_p_preferred_identity_t* p_preferred_identity=belle_sip_header_p_preferred_identity_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_from_address(op))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(p_preferred_identity)); + } + if (strcmp("REGISTER",method)!=0 && op->privacy!=SalPrivacyNone ){ + belle_sip_header_privacy_t* privacy_header=belle_sip_header_privacy_new(); + if (op->privacy&SalPrivacyCritical) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyCritical)); + if (op->privacy&SalPrivacyHeader) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyHeader)); + if (op->privacy&SalPrivacyId) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyId)); + if (op->privacy&SalPrivacyNone) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyNone)); + if (op->privacy&SalPrivacySession) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacySession)); + if (op->privacy&SalPrivacyUser) + belle_sip_header_privacy_add_privacy(privacy_header,sal_privacy_to_string(SalPrivacyUser)); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(privacy_header)); + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),sal_make_supported_header(op->base.root)); + return req; +} + +belle_sip_response_t *sal_op_create_response_from_request(SalOp *op, belle_sip_request_t *req, int code){ + return sal_create_response_from_request(op->base.root,req,code); +} + +/*ping: main purpose is to obtain its own contact address behind firewalls*/ +int sal_ping(SalOp *op, const char *from, const char *to){ + sal_op_set_from(op,from); + sal_op_set_to(op,to); + return sal_op_send_request(op,sal_op_build_request(op,"OPTIONS")); +} + +void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message) { + belle_sip_header_user_agent_t* user_agent=belle_sip_message_get_header_by_type(message,belle_sip_header_user_agent_t); + char user_agent_string[256]; + if(user_agent && belle_sip_header_user_agent_get_products_as_string(user_agent,user_agent_string,sizeof(user_agent_string))>0) { + op->base.remote_ua=ms_strdup(user_agent_string); + } +} + +int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires) { + belle_sip_header_expires_t* expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_EXPIRES); + + if (!expires_header && expires>=0) { + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new())); + } + if (expires_header) belle_sip_header_expires_set_expires(expires_header,expires); + return sal_op_send_request(op,request); +} + +void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { + belle_sip_header_cseq_t* cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ); + belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); + sal_op_send_request(op,request); +} + +static void add_headers(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 _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_free(l); + } +} + +static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request,bool_t add_contact) { + belle_sip_client_transaction_t* client_transaction; + belle_sip_provider_t* prov=op->base.root->prov; + belle_sip_uri_t* outbound_proxy=NULL; + belle_sip_header_contact_t* contact; + int result =-1; + belle_sip_uri_t *next_hop_uri=NULL; + + _sal_op_add_custom_headers(op, (belle_sip_message_t*)request); + + if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) { + /*don't put route header if dialog is in confirmed state*/ + const MSList *elem=sal_op_get_route_addresses(op); + const char *transport; + const char *method=belle_sip_request_get_method(request); + + if (elem) { + outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data); + next_hop_uri=outbound_proxy; + }else{ + next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request)); + } + transport=belle_sip_uri_get_transport_param(next_hop_uri); + if (transport==NULL){ + /*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use + * the first available transport*/ + if (!belle_sip_uri_is_secure(next_hop_uri)){ + if (belle_sip_provider_get_listening_point(prov,"UDP")==0){ + if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){ + transport="tcp"; + }else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){ + transport="tls"; + } + } + if (transport){ + belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport); + belle_sip_uri_set_transport_param(next_hop_uri,transport); + } + } + } + if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport && + (strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){ + /*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/ + belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t); + belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"alias",NULL); + } + } + + client_transaction = belle_sip_provider_create_client_transaction(prov,request); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op)); + if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans); + op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/ + belle_sip_object_ref(op->pending_client_trans); + + if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL) + belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent)); + + if (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); + } + result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/); + + /*update call id if not set yet for this OP*/ + if (result == 0 && !op->base.call_id) { + op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_call_id_t)))); + } + + return result; + +} + +int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { + bool_t need_contact=FALSE; + if (request==NULL) { + return -1; /*sanity check*/ + } + /* + Header field where proxy ACK BYE CAN INV OPT REG + ___________________________________________________________ + Contact R o - - m o o + */ + if (strcmp(belle_sip_request_get_method(request),"INVITE")==0 + ||strcmp(belle_sip_request_get_method(request),"REGISTER")==0 + ||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0 + ||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0 + ||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/ + need_contact=TRUE; + + return _sal_op_send_request_with_contact(op, request,need_contact); +} + +SalReason sal_reason_to_sip_code(SalReason r){ + int ret=500; + switch(r){ + case SalReasonUnknown: + ret=400; + break; + case SalReasonBusy: + ret=486; + break; + case SalReasonDeclined: + ret=603; + break; + case SalReasonDoNotDisturb: + ret=600; + break; + case SalReasonForbidden: + ret=403; + break; + case SalReasonMedia: + ret=415; + break; + case SalReasonNotFound: + ret=404; + break; + case SalReasonRedirect: + ret=302; + break; + case SalReasonTemporarilyUnavailable: + ret=480; + break; + case SalReasonServiceUnavailable: + ret=503; + break; + case SalReasonRequestPending: + ret=491; + break; + case SalReasonUnauthorized: + ret=401; + break; + case SalReasonNotAcceptable: + ret=488; + break; + } + return ret; +} + +void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal_reason) { + switch(code) { + case 400: + *sal_err=SalErrorUnknown; + break; + case 401: + case 407: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonUnauthorized; + break; + case 403: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonForbidden; + break; + case 404: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonNotFound; + break; + case 415: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonMedia; + break; + case 422: + ms_error ("422 not implemented yet");; + break; + case 480: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonTemporarilyUnavailable; + break; + case 486: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonBusy; + break; + case 487: + break; + case 488: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonNotAcceptable; + break; + case 491: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonRequestPending; + break; + case 600: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonDoNotDisturb; + break; + case 603: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonDeclined; + break; + case 503: + *sal_err=SalErrorFailure; + *sal_reason=SalReasonServiceUnavailable; + break; + 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 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 set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { + /*check if dialog has changed*/ + if (dialog && dialog != op->dialog) { + ms_message("Dialog set from [%p] to [%p] for op [%p]",op->dialog,dialog,op); + /*fixme, shouldn't we cancel previous dialog*/ + if (op->dialog) { + belle_sip_dialog_set_application_data(op->dialog,NULL); + belle_sip_object_unref(op->dialog); + sal_op_unref(op); + } + op->dialog=dialog; + belle_sip_dialog_set_application_data(op->dialog,op); + sal_op_ref(op); + belle_sip_object_ref(op->dialog); + } +} +/*return reffed op*/ +SalOp* sal_op_ref(SalOp* op) { + op->ref++; + return op; +} +/*return null, destroy op if ref count =0*/ +void* sal_op_unref(SalOp* op) { + op->ref--; + if (op->ref==0) { + sal_op_release_impl(op); + }else if (op->ref<0){ + ms_fatal("SalOp [%p]: too many unrefs.",op); + } + return NULL; +} + +int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ) { + if (sal_op_send_request_with_expires(op,req,expires)==0) { + if (op->refresher) { + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + } + if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { + belle_sip_refresher_set_listener(op->refresher,listener,op); + belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after); + belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher); + return 0; + } else { + return -1; + } + } + return -1; +} + +const char* sal_op_state_to_string(const SalOpState value) { + switch(value) { + case SalOpStateEarly: return"SalOpStateEarly"; + case SalOpStateActive: return "SalOpStateActive"; + case SalOpStateTerminating: return "SalOpStateTerminating"; + case SalOpStateTerminated: return "SalOpStateTerminated"; + default: + return "Unknown"; + } +} + +/* + * Warning: this function takes owneship of the custom headers + */ +void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch){ + SalOpBase *b=(SalOpBase *)op; + if (b->sent_custom_headers){ + sal_custom_header_free(b->sent_custom_headers); + b->sent_custom_headers=NULL; + } + if (ch) belle_sip_object_ref((belle_sip_message_t*)ch); + b->sent_custom_headers=ch; +} + +void sal_op_assign_recv_headers(SalOp *op, belle_sip_message_t *incoming){ + if (incoming) belle_sip_object_ref(incoming); + if (op->base.recv_custom_headers){ + belle_sip_object_unref(op->base.recv_custom_headers); + op->base.recv_custom_headers=NULL; + } + if (incoming){ + op->base.recv_custom_headers=(SalCustomHeader*)incoming; + } +} + +const char *sal_op_get_remote_contact(const SalOp *op){ + return sal_custom_header_find(op->base.recv_custom_headers,"Contact"); +} + +void sal_op_add_body(SalOp *op, belle_sip_message_t *req, const SalBody *body){ + belle_sip_message_remove_header((belle_sip_message_t*)req,"Content-type"); + belle_sip_message_remove_header((belle_sip_message_t*)req,"Content-length"); + belle_sip_message_remove_header((belle_sip_message_t*)req,"Content-encoding"); + belle_sip_message_set_body((belle_sip_message_t*)req,NULL,0); + if (body && body->type && body->subtype && body->data){ + belle_sip_message_add_header((belle_sip_message_t*)req, + (belle_sip_header_t*)belle_sip_header_content_type_create(body->type,body->subtype)); + belle_sip_message_add_header((belle_sip_message_t*)req, + (belle_sip_header_t*)belle_sip_header_content_length_create(body->size)); + belle_sip_message_set_body((belle_sip_message_t*)req,(const char*)body->data,body->size); + if (body->encoding){ + belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*) + belle_sip_header_create("Content-encoding",body->encoding)); + } + } +} + + +bool_t sal_op_get_body(SalOp *op, belle_sip_message_t *msg, SalBody *salbody){ + const char *body = NULL; + belle_sip_header_content_type_t *content_type; + belle_sip_header_content_length_t *clen=NULL; + belle_sip_header_t *content_encoding; + + content_type=belle_sip_message_get_header_by_type(msg,belle_sip_header_content_type_t); + if (content_type){ + body=belle_sip_message_get_body(msg); + clen=belle_sip_message_get_header_by_type(msg,belle_sip_header_content_length_t); + } + content_encoding=belle_sip_message_get_header(msg,"Content-encoding"); + + memset(salbody,0,sizeof(SalBody)); + + if (content_type && body && clen) { + salbody->type=belle_sip_header_content_type_get_type(content_type); + salbody->subtype=belle_sip_header_content_type_get_subtype(content_type); + salbody->data=body; + salbody->size=belle_sip_header_content_length_get_content_length(clen); + if (content_encoding) + salbody->encoding=belle_sip_header_get_unparsed_value(content_encoding); + return TRUE; + } + return FALSE; +} + +void sal_op_set_privacy(SalOp* op,SalPrivacyMask privacy) { + op->privacy=privacy; +} +SalPrivacyMask sal_op_get_privacy(const SalOp* op) { + return op->privacy; +} + +bool_t sal_op_is_secure(const SalOp* op) { + const SalAddress* from = sal_op_get_from_address(op); + const SalAddress* to = sal_op_get_to_address(op); + + return from && to && strcasecmp("sips",sal_address_get_scheme(from))==0 && strcasecmp("sips",sal_address_get_scheme(to))==0; +} + +void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled){ + op->manual_refresher=enabled; +} diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c new file mode 100644 index 000000000..9abc73818 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_info.c @@ -0,0 +1,30 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" + + +int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body){ + if (op->dialog){ + belle_sip_request_t *req=belle_sip_dialog_create_queued_request(op->dialog,"INFO"); + sal_op_add_body(op,(belle_sip_message_t*)req,body); + return sal_op_send_request(op,req); + } + return -1; +} + diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c new file mode 100644 index 000000000..1e3dc12f0 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -0,0 +1,170 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" + +static void process_error( SalOp* op) { + if (op->dir == SalOpDirOutgoing) { + op->base.root->callbacks.text_delivery_update(op,SalTextDeliveryFailed); + } else { + ms_warning("unexpected io error for incoming message on op [%p]",op); + } + op->state=SalOpStateTerminated; + +} + +static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + SalOp* op = (SalOp*)user_ctx; +// 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); +// } + 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); +// } + 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; + 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; +} +static bool_t is_external_body(belle_sip_header_content_type_t* content_type) { + return strcmp("message",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("external-body",belle_sip_header_content_type_get_subtype(content_type))==0; +} + +static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { + SalOp* op = (SalOp*)op_base; + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); + belle_sip_header_address_t* address; + belle_sip_header_from_t* from_header; + belle_sip_header_content_type_t* content_type; + belle_sip_response_t* resp; + 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; + + from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); + content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); + if (content_type && ((plain_text=is_plain_text(content_type)) + || (external_body=is_external_body(content_type)))) { + + address=belle_sip_header_address_create(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(from_header)) + ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from_header))); + from=belle_sip_object_to_string(BELLE_SIP_OBJECT(address)); + snprintf(message_id,sizeof(message_id)-1,"%s%i" + ,belle_sip_header_call_id_get_call_id(call_id) + ,belle_sip_header_cseq_get_seq_number(cseq)); + salmsg.from=from; + salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + salmsg.url=NULL; + if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) { + size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")); + salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/ + ((char*)salmsg.url)[url_length-2]='\0'; /*remove trailing "*/ + } + salmsg.message_id=message_id; + salmsg.time=date ? belle_sip_header_date_get_time(date) : time(NULL); + op->base.root->callbacks.text_received(op,&salmsg); + belle_sip_object_unref(address); + belle_sip_free(from); + if (salmsg.url) ms_free((char*)salmsg.url); + response_code=200; + } 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*/ + } + resp = belle_sip_response_create_from_request(req,response_code); + belle_sip_server_transaction_send_response(server_transaction,resp); + sal_op_release(op); +} + +int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ + belle_sip_request_t* req; + char content_type_raw[256]; + 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; + + 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))); + } + snprintf(content_type_raw,sizeof(content_type_raw),BELLE_SIP_CONTENT_TYPE ": %s",content_type); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_type_parse(content_type_raw))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),msg,content_length); + return sal_op_send_request(op,req); + +} + +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); +} + +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; + op->type=SalOpMessage; +} diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c new file mode 100644 index 000000000..bdc58388b --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -0,0 +1,363 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" + + +void sal_add_presence_info(SalOp *op, belle_sip_message_t *notify, SalPresenceModel *presence) { + char *contact_info; + char *content = NULL; + size_t content_length; + + if (presence){ + belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(notify,belle_sip_header_from_t); + contact_info=belle_sip_uri_to_string(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from))); + op->base.root->callbacks.convert_presence_to_xml_requested(op, presence, contact_info, &content); + ms_free(contact_info); + if (content == NULL) return; + } + + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_TYPE); + belle_sip_message_remove_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_CONTENT_LENGTH); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),NULL,0); + + if (content){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","pidf+xml"))); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length=strlen(content)))); + belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),content,content_length); + ms_free(content); + } + + +} + +static void presence_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ + ms_error("presence_process_io_error not implemented yet"); +} + +static void presence_process_dialog_terminated(void *ctx, const belle_sip_dialog_terminated_event_t *event) { + SalOp* op= (SalOp*)ctx; + if (op->dialog) { + sal_op_unref(op); + op->dialog=NULL; + } +} + +static void presence_refresher_listener(belle_sip_refresher_t* refresher, void* user_pointer, unsigned int status_code, const char* reason_phrase){ + SalOp* op = (SalOp*)user_pointer; + switch(status_code){ + case 481: { + + ms_message("The server or remote ua lost the SUBSCRIBE dialog context. Let's restart a new one."); + belle_sip_refresher_stop(op->refresher); + if (op->dialog) { /*delete previous dialog if any*/ + belle_sip_dialog_set_application_data(op->dialog,NULL); + belle_sip_object_unref(op->dialog); + op->dialog=NULL; + } + + if (sal_op_get_contact_address(op)) { + /*contact is also probably not good*/ + SalAddress* contact=sal_address_clone(sal_op_get_contact_address(op)); + sal_address_set_port(contact,-1); + sal_address_set_domain(contact,NULL); + sal_op_set_contact_address(op,contact); + sal_address_destroy(contact); + } + + sal_subscribe_presence(op,NULL,NULL,-1); + break; + } + } +} + + +static void presence_response_event(void *op_base, const belle_sip_response_event_t *event){ + SalOp* op = (SalOp*)op_base; + belle_sip_dialog_state_t dialog_state; + belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); + belle_sip_response_t* response=belle_sip_response_event_get_response(event); + belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); + int code = belle_sip_response_get_status_code(response); + char reason[256]={0}; + SalError error=SalErrorUnknown; + SalReason sr=SalReasonUnknown; + belle_sip_header_expires_t* expires; + + 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)); + op->base.root->callbacks.notify_presence(op,SalSubscribeTerminated, NULL,NULL); /*NULL = offline*/ + return; + } + set_or_update_dialog(op_base,belle_sip_response_event_get_dialog(event)); + if (!op->dialog) { + ms_message("presence op [%p] receive out of dialog answer [%i]",op,code); + return; + } + dialog_state=belle_sip_dialog_get_state(op->dialog); + + switch(dialog_state) { + case BELLE_SIP_DIALOG_NULL: + case BELLE_SIP_DIALOG_EARLY: { + ms_error("presence op [%p] receive an unexpected answer [%i]",op,code); + break; + } + case BELLE_SIP_DIALOG_CONFIRMED: { + if (strcmp("SUBSCRIBE",belle_sip_request_get_method(request))==0) { + expires=belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t); + if(op->refresher) { + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + } + if (expires>0){ + op->refresher=belle_sip_client_transaction_create_refresher(client_transaction); + belle_sip_refresher_set_listener(op->refresher,presence_refresher_listener,op); + } + } + break; + } + case BELLE_SIP_DIALOG_TERMINATED: + if (op->refresher) { + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + } + break; + default: { + ms_error("presence op [%p] receive answer [%i] not implemented",op,code); + } + /* no break */ + } + + +} +static void presence_process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { + ms_error("presence_process_timeout not implemented yet"); +} + +static void presence_process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { + ms_message("presence_process_transaction_terminated not implemented yet"); +} + +static SalPresenceModel * process_presence_notification(SalOp *op, belle_sip_request_t *req) { + belle_sip_header_content_type_t *content_type = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_type_t); + belle_sip_header_content_length_t *content_length = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req), belle_sip_header_content_length_t); + const char *body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + SalPresenceModel *result = NULL; + + if ((content_type == NULL) || (content_length == NULL)) + return NULL; + if (belle_sip_header_content_length_get_content_length(content_length) == 0) + return NULL; + + op->base.root->callbacks.parse_presence_requested(op, + belle_sip_header_content_type_get_type(content_type), + belle_sip_header_content_type_get_subtype(content_type), + body, + &result); + + return result; +} + +static void handle_notify(SalOp *op, belle_sip_request_t *req){ + belle_sip_response_t* resp; + belle_sip_server_transaction_t* server_transaction=op->pending_server_trans; + belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t); + SalSubscribeStatus sub_state; + + if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { + SalPresenceModel *presence_model = NULL; + const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + if (body==NULL){ + ms_error("No body in NOTIFY received from [%s]",sal_op_get_from(op)); + resp = sal_op_create_response_from_request(op, req, 415); + belle_sip_server_transaction_send_response(server_transaction,resp); + return; + } + presence_model = process_presence_notification(op, req); + if (presence_model != NULL) { + /* Presence notification body parsed successfully. */ + if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) { + sub_state=SalSubscribeTerminated; + ms_message("Outgoing subscription terminated by remote [%s]",sal_op_get_to(op)); + } else { + sub_state=SalSubscribeActive; + } + resp = sal_op_create_response_from_request(op, req, 200); /*create first because the op may be destroyed by notify_presence */ + op->base.root->callbacks.notify_presence(op, sub_state, presence_model, NULL); + + } else { + /* Formatting error in presence notification body. */ + ms_error("Wrongly formatted presence notification received"); + resp = sal_op_create_response_from_request(op, req, 400); + } + belle_sip_server_transaction_send_response(server_transaction,resp); + } +} + +static void presence_process_request_event(void *op_base, const belle_sip_request_event_t *event) { + SalOp* op = (SalOp*)op_base; + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_dialog_state_t dialog_state; + belle_sip_header_expires_t* expires = belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t); + belle_sip_response_t* resp; + const char *method=belle_sip_request_get_method(req); + + belle_sip_object_ref(server_transaction); + if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); + op->pending_server_trans=server_transaction; + + + if (!op->dialog) { + if (strcmp(method,"SUBSCRIBE")==0){ + op->dialog=belle_sip_provider_create_dialog(op->base.root->prov,BELLE_SIP_TRANSACTION(server_transaction)); + belle_sip_dialog_set_application_data(op->dialog,op); + sal_op_ref(op); + ms_message("new incoming subscription from [%s] to [%s]",sal_op_get_from(op),sal_op_get_to(op)); + }else{ /* this is a NOTIFY */ + ms_message("Receiving out of dialog notify"); + handle_notify(op,req); + return; + } + } + dialog_state=belle_sip_dialog_get_state(op->dialog); + switch(dialog_state) { + case BELLE_SIP_DIALOG_NULL: { + op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op)); + break; + } + case BELLE_SIP_DIALOG_EARLY: + ms_error("unexpected method [%s] for dialog [%p] in state BELLE_SIP_DIALOG_EARLY ",method,op->dialog); + break; + + case BELLE_SIP_DIALOG_CONFIRMED: + if (strcmp("NOTIFY",method)==0) { + handle_notify(op,req); + } else if (strcmp("SUBSCRIBE",method)==0) { + /*either a refresh or an unsubscribe*/ + if (expires && belle_sip_header_expires_get_expires(expires)>0) { + op->base.root->callbacks.subscribe_presence_received(op,sal_op_get_from(op)); + } else if(expires) { + ms_message("Unsubscribe received from [%s]",sal_op_get_from(op)); + resp=sal_op_create_response_from_request(op,req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + } + } + break; + default: + ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); + break; + } +} + +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; + op->type=SalOpPresence; +} + + +/*presence Subscribe/notify*/ +int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expires){ + belle_sip_request_t *req=NULL; + if (from) + sal_op_set_from(op,from); + if (to) + sal_op_set_to(op,to); + + sal_op_presence_fill_cbs(op); + + if (expires==-1){ + if (op->refresher){ + expires=belle_sip_refresher_get_expires(op->refresher); + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + }else{ + ms_error("sal_subscribe_presence(): cannot guess expires from previous refresher."); + return -1; + } + } + if (!op->event){ + op->event=belle_sip_header_create("Event","presence"); + belle_sip_object_ref(op->event); + } + belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.from_address),"tag"); + belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(op->base.to_address),"tag"); + req=sal_op_build_request(op,"SUBSCRIBE"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires))); + + return sal_op_send_request(op,req); +} + + +static belle_sip_request_t *create_presence_notify(SalOp *op){ + belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"); + if (!notify) return NULL; + + belle_sip_message_add_header((belle_sip_message_t*)notify,belle_sip_header_create("Event","presence")); + return notify; +} + +static int sal_op_check_dialog_state(SalOp *op) { + belle_sip_dialog_state_t state=op->dialog?belle_sip_dialog_get_state(op->dialog): BELLE_SIP_DIALOG_NULL; + if (state != BELLE_SIP_DIALOG_CONFIRMED) { + ms_warning("Cannot notify presence for op [%p] because dialog in state [%s]",op, belle_sip_dialog_state_to_string(state)); + return -1; + } else + return 0; + +} +int sal_notify_presence(SalOp *op, SalPresenceModel *presence){ + belle_sip_request_t* notify=NULL; + if (sal_op_check_dialog_state(op)) { + return -1; + } + notify=create_presence_notify(op); + if (!notify) return-1; + + sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),presence); /*FIXME, what about expires ??*/ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,600))); + return sal_op_send_request(op,notify); +} + +int sal_notify_presence_close(SalOp *op){ + belle_sip_request_t* notify=NULL; + if (sal_op_check_dialog_state(op)) { + return -1; + } + notify=create_presence_notify(op); + if (!notify) return-1; + + sal_add_presence_info(op,BELLE_SIP_MESSAGE(notify),NULL); /*FIXME, what about expires ??*/ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify) + ,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1))); + return sal_op_send_request(op,notify); +} + + + diff --git a/coreapi/bellesip_sal/sal_op_publish.c b/coreapi/bellesip_sal/sal_op_publish.c new file mode 100644 index 000000000..196167095 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_publish.c @@ -0,0 +1,114 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" + + +static void publish_refresher_listener (belle_sip_refresher_t* refresher + ,void* user_pointer + ,unsigned int status_code + ,const char* reason_phrase) { + SalOp* op = (SalOp*)user_pointer; + /*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); + } +} + +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); +} + +void sal_op_publish_fill_cbs(SalOp*op) { + op->callbacks.process_response_event=publish_response_event; + op->type=SalOpPublish; +} + +/* + * Sending a publish with 0 expires removes the event state and such request shall not contain a body. + * See RFC3903, section 4.5 + */ + +/*presence publish */ +int sal_publish_presence(SalOp *op, const char *from, const char *to, int expires, SalPresenceModel *presence){ + belle_sip_request_t *req=NULL; + if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) { + if (from) + sal_op_set_from(op,from); + if (to) + sal_op_set_to(op,to); + + op->type=SalOpPublish; + req=sal_op_build_request(op,"PUBLISH"); + if (sal_op_get_contact(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")); + sal_add_presence_info(op,BELLE_SIP_MESSAGE(req),presence); + return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener); + } else { + /*update presence status*/ + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); + sal_add_presence_info(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? presence : NULL); + return belle_sip_refresher_refresh(op->refresher,expires); + } +} + +int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){ + belle_sip_request_t *req=NULL; + if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) { + if (from) + sal_op_set_from(op,from); + if (to) + sal_op_set_to(op,to); + + sal_op_publish_fill_cbs(op); + req=sal_op_build_request(op,"PUBLISH"); + if (sal_op_get_contact(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); + } else { + /*update status*/ + const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher); + belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans)); + /*update body*/ + sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? body : NULL); + return belle_sip_refresher_refresh(op->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires); + } +} diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c new file mode 100644 index 000000000..c02546019 --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -0,0 +1,108 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" + + +static void register_refresher_listener (belle_sip_refresher_t* refresher + ,void* user_pointer + ,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)); + + if (belle_sip_refresher_get_auth_events(refresher)) { + if (op->auth_info) sal_auth_info_delete(op->auth_info); + /*only take first one for now*/ + op->auth_info=sal_auth_info_create((belle_sip_auth_event_t*)(belle_sip_refresher_get_auth_events(refresher)->data)); + } + if(status_code == 200) { + /*check service route rfc3608*/ + belle_sip_header_service_route_t* service_route; + belle_sip_header_address_t* service_route_address=NULL; + if ((service_route=belle_sip_message_get_header_by_type(response,belle_sip_header_service_route_t))) { + service_route_address=belle_sip_header_address_create(NULL,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(service_route))); + } + sal_op_set_service_route(op,(const SalAddress*)service_route_address); + if (service_route_address) belle_sip_object_unref(service_route_address); + + sal_remove_pending_auth(op->base.root,op); /*just in case*/ + op->base.root->callbacks.register_success(op,belle_sip_refresher_get_expires(op->refresher)>0); + } else if (status_code>=400) { + /* from rfc3608, 6.1. + If the UA refreshes the registration, the stored value of the Service- + Route is updated according to the Service-Route header field of the + latest 200 class response. If there is no Service-Route header field + in the response, the UA clears any service route for that address- + of-record previously stored by the UA. If the re-registration + request is refused or if an existing registration expires and the UA + 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); + if (op->auth_info) { + /*add pending auth*/ + sal_add_pending_auth(op->base.root,op); + if (status_code==403) + op->base.root->callbacks.auth_failure(op,op->auth_info); + } + } +} + +int sal_register(SalOp *op, const char *proxy, const char *from, int expires){ + belle_sip_request_t *req; + belle_sip_uri_t* req_uri; + + if (op->refresher){ + belle_sip_refresher_stop(op->refresher); + belle_sip_object_unref(op->refresher); + op->refresher=NULL; + } + + op->type=SalOpRegister; + sal_op_set_from(op,from); + sal_op_set_to(op,from); + sal_op_set_route(op,proxy); + req = sal_op_build_request(op,"REGISTER"); + req_uri = belle_sip_request_get_uri(req); + belle_sip_uri_set_user(req_uri,NULL); /*remove userinfo if any*/ + if (op->base.root->use_dates){ + time_t curtime=time(NULL); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime))); + } + belle_sip_message_set_header(BELLE_SIP_MESSAGE(req),(belle_sip_header_t*)sal_op_create_contact(op)); + return sal_op_send_and_create_refresher(op,req,expires,register_refresher_listener); +} + +int sal_register_refresh(SalOp *op, int expires){ + if (op->refresher) + return belle_sip_refresher_refresh(op->refresher,expires); + else + return -1; +} + +int sal_unregister(SalOp *op){ + return sal_register_refresh(op,0); +} + + diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c new file mode 100644 index 000000000..c01d1d83b --- /dev/null +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -0,0 +1,496 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" +#define keywordcmp(key,b) strncmp(key,b,sizeof(key)) + + +static void add_ice_candidates(belle_sdp_media_description_t *md, const SalStreamDescription *desc){ + char buffer[1024]; + const SalIceCandidate *candidate; + int nb; + int i; + + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; i++) { + candidate = &desc->ice_candidates[i]; + if ((candidate->addr[0] == '\0') || (candidate->port == 0)) break; + nb = snprintf(buffer, sizeof(buffer), "%s %u UDP %u %s %d typ %s", + candidate->foundation, candidate->componentID, candidate->priority, candidate->addr, candidate->port, candidate->type); + if (nb < 0) { + ms_error("Cannot add ICE candidate attribute!"); + return; + } + if (candidate->raddr[0] != '\0') { + nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport); + if (nb < 0) { + ms_error("Cannot add ICE candidate attribute!"); + return; + } + } + belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("candidate",buffer)); + } +} + +static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const SalStreamDescription *desc){ + char buffer[1024]; + char *ptr = buffer; + const SalIceRemoteCandidate *candidate; + int offset = 0; + int i; + + buffer[0] = '\0'; + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) { + candidate = &desc->ice_remote_candidates[i]; + if ((candidate->addr[0] != '\0') && (candidate->port != 0)) { + offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port); + if (offset < 0) { + ms_error("Cannot add ICE remote-candidates attribute!"); + return; + } + ptr += offset; + } + } + 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 ) { + belle_sdp_mime_parameter_t* mime_param; + belle_sdp_media_description_t* media_desc; + int j; + MSList* pt_it; + PayloadType* pt; + char buffer[1024]; + char* dir=NULL; + const char *rtp_addr; + const char *rtcp_addr; + int rtp_port; + int rtcp_port; + bool_t different_rtp_and_rtcp_addr; + + rtp_addr=stream->rtp_addr; + rtcp_addr=stream->rtcp_addr; + rtp_port=stream->rtp_port; + rtcp_port=stream->rtcp_port; + + media_desc = belle_sdp_media_description_create ( sal_stream_type_to_string ( stream->type ) + ,stream->rtp_port + ,1 + ,sal_media_proto_to_string ( stream->proto ) + ,NULL ); + if (stream->payloads) { + for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) { + pt= ( PayloadType* ) pt_it->data; + mime_param= belle_sdp_mime_parameter_create ( pt->mime_type + , payload_type_get_number ( pt ) + , pt->clock_rate + ,stream->type==SalAudio?1:-1 ); + belle_sdp_mime_parameter_set_parameters ( mime_param,pt->recv_fmtp ); + if ( stream->ptime>0 ) { + belle_sdp_mime_parameter_set_ptime ( mime_param,stream->ptime ); + } + belle_sdp_media_description_append_values_from_mime_parameter ( media_desc,mime_param ); + belle_sip_object_unref ( mime_param ); + } + } else { + /* to comply with SDP we cannot have an empty payload type number list */ + /* as it happens only when mline is declined with a zero port, it does not matter to put whatever codec*/ + belle_sip_list_t* format = belle_sip_list_append(NULL,0); + belle_sdp_media_set_media_formats(belle_sdp_media_description_get_media(media_desc),format); + } + /*only add a c= line within the stream description if address are differents*/ + if (rtp_addr[0]!='\0' && strcmp(rtp_addr,md->addr)!=0){ + bool_t inet6; + if (strchr(rtp_addr,':')!=NULL){ + inet6=TRUE; + }else inet6=FALSE; + belle_sdp_media_description_set_connection(media_desc,belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr)); + } + + if ( stream->bandwidth>0 ) + belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth ); + + if ( stream->proto == SalProtoRtpSavp ) { + /* add crypto lines */ + for ( j=0; jcrypto[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 ) ); + 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 ) ); + break; + case AES_128_NO_AUTH: + ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" ); + break; + case NO_CIPHER_SHA1_80: + ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" ); + break; + default: + j = SAL_CRYPTO_ALGO_MAX; + /* no break */ + } + } + } + switch ( stream->dir ) { + case SalStreamSendRecv: + /*dir="sendrecv";*/ + dir=NULL; + break; + case SalStreamRecvOnly: + dir="recvonly"; + break; + case SalStreamSendOnly: + dir="sendonly"; + break; + case SalStreamInactive: + dir="inactive"; + break; + } + if ( dir ) belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( dir,NULL ) ); + + if (rtp_port != 0) { + different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0); + if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) { + if (different_rtp_and_rtcp_addr == TRUE) { + snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); + } else { + snprintf(buffer, sizeof(buffer), "%u",rtcp_port); + } + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("rtcp",buffer)); + } + } + if (stream->ice_completed == TRUE) { + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("nortpproxy","yes")); + } + if (stream->ice_mismatch == TRUE) { + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-mismatch",NULL)); + } else { + if (rtp_port != 0) { + if (stream->ice_pwd[0] != '\0') + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-pwd",stream->ice_pwd)); + if (stream->ice_ufrag[0] != '\0') + belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-ufrag",stream->ice_ufrag)); + add_ice_candidates(media_desc,stream); + add_ice_remote_candidates(media_desc,stream); + } + } + + return media_desc; +} + +belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescription *desc ) { + belle_sdp_session_description_t* session_desc=belle_sdp_session_description_new(); + bool_t inet6; + belle_sdp_origin_t* origin; + int i; + + if ( strchr ( desc->addr,':' ) !=NULL ) { + inet6=1; + } else inet6=0; + belle_sdp_session_description_set_version ( session_desc,belle_sdp_version_create ( 0 ) ); + + origin = belle_sdp_origin_create ( desc->username + ,desc->session_id + ,desc->session_ver + ,"IN" + , inet6 ? "IP6" :"IP4" + ,desc->addr ); + + belle_sdp_session_description_set_origin ( session_desc,origin ); + + belle_sdp_session_description_set_session_name ( session_desc,belle_sdp_session_name_create ( "Talk" ) ); + + if ( (!sal_media_description_has_dir ( desc,SalStreamSendOnly ) && !sal_media_description_has_dir ( desc,SalStreamInactive )) + || desc->ice_ufrag[0] != '\0' ) { + belle_sdp_session_description_set_connection ( session_desc + ,belle_sdp_connection_create ( "IN",inet6 ? "IP6" :"IP4",desc->addr ) ); + + } else { + belle_sdp_session_description_set_connection ( session_desc + ,belle_sdp_connection_create ( "IN" + ,inet6 ? "IP6" :"IP4" + ,inet6 ? "::0" :"0.0.0.0" ) ); + + } + + belle_sdp_session_description_set_time_description ( session_desc,belle_sdp_time_description_create ( 0,0 ) ); + + if ( desc->bandwidth>0 ) { + belle_sdp_session_description_set_bandwidth ( session_desc,"AS",desc->bandwidth ); + } + + 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)); + + for ( i=0; in_total_streams; i++ ) { + belle_sdp_session_description_add_media_description ( session_desc,stream_description_to_sdp(desc,&desc->streams[i])); + } + return session_desc; +} + + +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; + const char* value; + + desc->n_active_streams = 0; + desc->n_total_streams = 0; + + 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 ) ); + } + 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; + } else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) { + stream_dir=SalStreamSendOnly; + } else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) { + stream_dir=SalStreamRecvOnly; + } else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) { + stream_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)); + + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd"); + if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)); + + value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); + if (value) desc->ice_lite = TRUE; + + 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; + 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 (ptrice_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++; + } + return 0; +} + + + + + diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a6b49a0e8..da674aac6 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -18,36 +18,35 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "sal.h" +#include "sal/sal.h" #include "linphonecore.h" #include "private.h" #include "mediastreamer2/mediastream.h" #include "lpconfig.h" +// stat +#ifndef WIN32 +#include +#include +#include +#endif + static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); 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; if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_CHANGED; - return sal_media_description_equals(oldmd, newmd); + if (call->localdesc_changed) ms_message("Local description has changed: %i", call->localdesc_changed); + return call->localdesc_changed | sal_media_description_equals(oldmd, newmd); } void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { - SalStreamDescription *old_audiodesc = NULL; - SalStreamDescription *old_videodesc = NULL; SalStreamDescription *new_audiodesc = NULL; SalStreamDescription *new_videodesc = NULL; char *rtp_addr, *rtcp_addr; int i; - for (i = 0; i < old_md->n_active_streams; i++) { - if (old_md->streams[i].type == SalAudio) { - old_audiodesc = &old_md->streams[i]; - } else if (old_md->streams[i].type == SalVideo) { - old_videodesc = &old_md->streams[i]; - } - } for (i = 0; i < new_md->n_active_streams; i++) { if (new_md->streams[i].type == SalAudio) { new_audiodesc = &new_md->streams[i]; @@ -68,31 +67,15 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c 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); } +#else + (void)new_videodesc; #endif - - /* Copy address and port values from new_md to old_md since we will keep old_md as resultdesc */ - strcpy(old_md->addr, new_md->addr); - if (old_audiodesc && new_audiodesc) { - strcpy(old_audiodesc->rtp_addr, new_audiodesc->rtp_addr); - strcpy(old_audiodesc->rtcp_addr, new_audiodesc->rtcp_addr); - old_audiodesc->rtp_port = new_audiodesc->rtp_port; - old_audiodesc->rtcp_port = new_audiodesc->rtcp_port; - } - if (old_videodesc && new_videodesc) { - strcpy(old_videodesc->rtp_addr, new_videodesc->rtp_addr); - strcpy(old_videodesc->rtcp_addr, new_videodesc->rtcp_addr); - old_videodesc->rtp_port = new_videodesc->rtp_port; - old_videodesc->rtcp_port = new_videodesc->rtcp_port; - } } void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ SalMediaDescription *oldmd=call->resultdesc; - if (lc->ringstream!=NULL){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); if (new_md!=NULL){ sal_media_description_ref(new_md); call->media_pending=FALSE; @@ -108,24 +91,20 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia ms_message("Media descriptions are different, need to restart the streams."); } else { if (md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) { - /*as nothing has changed, keep the oldmd */ - call->resultdesc=oldmd; - sal_media_description_unref(new_md); if (call->all_muted){ ms_message("Early media finished, unmuting inputs..."); /*we were in early media, now we want to enable real media */ linphone_call_enable_camera (call,linphone_call_camera_enabled (call)); if (call->audiostream) - linphone_core_mute_mic (lc, linphone_core_is_mic_muted(lc)); + linphone_core_enable_mic(lc, linphone_core_mic_enabled(lc)); #ifdef VIDEO_ENABLED if (call->videostream && call->camera_active) video_stream_change_camera(call->videostream,lc->video_conf.device ); #endif } ms_message("No need to restart streams, SDP is unchanged."); - return; - } - else { + goto end; + }else { if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) { ms_message("Network parameters have changed, update them."); linphone_core_update_streams_destinations(lc, call, oldmd, new_md); @@ -134,17 +113,13 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia ms_message("Crypto parameters have changed, update them."); linphone_call_update_crypto_parameters(call, oldmd, new_md); } - call->resultdesc = oldmd; - sal_media_description_unref(new_md); - return; + goto end; } } } linphone_call_stop_media_streams (call); linphone_call_init_media_streams (call); } - if (oldmd) - sal_media_description_unref(oldmd); if (new_md) { bool_t all_muted=FALSE; @@ -166,6 +141,10 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){ linphone_core_play_named_tone(lc,LinphoneToneCallOnHold); } + end: + if (oldmd) + sal_media_description_unref(oldmd); + } #if 0 static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to){ @@ -182,9 +161,9 @@ static bool_t is_duplicate_call(LinphoneCore *lc, const LinphoneAddress *from, c #endif static bool_t already_a_call_with_remote_address(const LinphoneCore *lc, const LinphoneAddress *remote) { + MSList *elem; ms_warning(" searching for already_a_call_with_remote_address."); - MSList *elem; for(elem=lc->calls;elem!=NULL;elem=elem->next){ const LinphoneCall *call=(LinphoneCall*)elem->data; const LinphoneAddress *cRemote=linphone_call_get_remote_address(call); @@ -215,25 +194,37 @@ static void call_received(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneCall *call; 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); /* first check if we can answer successfully to this invite */ - if (lc->presence_mode==LinphoneStatusBusy || - lc->presence_mode==LinphoneStatusOffline || - lc->presence_mode==LinphoneStatusDoNotDisturb || - lc->presence_mode==LinphoneStatusMoved){ - if (lc->presence_mode==LinphoneStatusBusy ) - sal_call_decline(h,SalReasonBusy,NULL); - else if (lc->presence_mode==LinphoneStatusOffline) - sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); - else if (lc->presence_mode==LinphoneStatusDoNotDisturb) - sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); - else if (lc->alt_contact!=NULL && lc->presence_mode==LinphoneStatusMoved) - sal_call_decline(h,SalReasonRedirect,lc->alt_contact); + if (linphone_presence_model_get_basic_status(lc->presence_model) == LinphonePresenceBasicStatusClosed) { + LinphonePresenceActivity *activity = linphone_presence_model_get_activity(lc->presence_model); + switch (linphone_presence_activity_get_type(activity)) { + case LinphonePresenceActivityBusy: + sal_call_decline(h,SalReasonBusy,NULL); + break; + case LinphonePresenceActivityAppointment: + case LinphonePresenceActivityMeeting: + case LinphonePresenceActivityOffline: + case LinphonePresenceActivityWorship: + sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL); + break; + case LinphonePresenceActivityPermanentAbsence: + alt_contact = linphone_presence_model_get_contact(lc->presence_model); + if (alt_contact != NULL) { + sal_call_decline(h,SalReasonRedirect,alt_contact); + ms_free(alt_contact); + } + break; + default: + break; + } sal_op_release(h); return; } + if (!linphone_core_can_we_add_call(lc)){/*busy*/ sal_call_decline(h,SalReasonBusy,NULL); sal_op_release(h); @@ -282,17 +273,16 @@ static void call_ringing(SalOp *h){ if (call==NULL) return; + /*set privacy*/ + call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Remote ringing.")); md=sal_call_get_final_media_description(h); if (md==NULL){ - if (lc->ringstream && lc->dmfs_playing_start_time!=0){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - lc->dmfs_playing_start_time=0; - } - if (lc->ringstream!=NULL) return; /*already ringing !*/ + linphone_core_stop_dtmf_stream(lc); + if (lc->ringstream!=NULL) return;/*already ringing !*/ if (lc->sound_conf.play_sndcard!=NULL){ MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; if (call->localdesc->streams[0].max_rate>0) ms_snd_card_set_preferred_sample_rate(ringcard, call->localdesc->streams[0].max_rate); @@ -316,10 +306,7 @@ static void call_ringing(SalOp *h){ if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Early media.")); linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media"); - if (lc->ringstream!=NULL){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); ms_message("Doing early media..."); linphone_core_update_streams(lc,call,md); } @@ -339,6 +326,8 @@ static void call_accepted(SalOp *op){ ms_warning("No call to accept."); return ; } + /*set privacy*/ + call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); /* Handle remote ICE attributes if any. */ if (call->ice_session != NULL) { @@ -351,7 +340,7 @@ static void call_accepted(SalOp *op){ #endif //BUILD_UPNP md=sal_call_get_final_media_description(op); - if (md) + if (md) /*make sure re-invite will not propose video again*/ call->params.has_video &= linphone_core_media_description_contains_video_stream(md); if (call->state==LinphoneCallOutgoingProgress || @@ -402,7 +391,10 @@ static void call_accepted(SalOp *op){ } } } - linphone_core_update_streams (lc,call,md); + linphone_core_update_streams(lc,call,md); + /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again + * further in the call, for example during pause,resume, conferencing reINVITEs*/ + linphone_call_fix_call_parameters(call); if (!call->current_params.in_conference) lc->current_call=call; linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running"); @@ -451,8 +443,9 @@ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ linphone_call_update_remote_session_id_and_ver(call); sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); - if (md && !sal_media_description_empty(md)) + if (md && !sal_media_description_empty(md)){ linphone_core_update_streams(lc,call,md); + } } static void call_resumed(LinphoneCore *lc, LinphoneCall *call){ @@ -460,7 +453,6 @@ static void call_resumed(LinphoneCore *lc, LinphoneCall *call){ if(lc->vtable.display_status) lc->vtable.display_status(lc,_("We have been resumed.")); linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); - linphone_call_set_transfer_state(call, LinphoneCallIdle); } static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){ @@ -472,6 +464,16 @@ static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){ } static void call_updated_by_remote(LinphoneCore *lc, LinphoneCall *call){ + /*first check if media capabilities are compatible*/ + SalMediaDescription* md; + linphone_call_make_local_media_description(lc,call); + sal_call_set_local_media_description(call->op,call->localdesc); + md=sal_call_get_final_media_description(call->op); + if (md && (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md))){ + sal_call_decline(call->op,SalReasonNotAcceptable,NULL); + return; + } + if(lc->vtable.display_status) lc->vtable.display_status(lc,_("Call is updated by remote.")); call->defer_update=FALSE; @@ -533,10 +535,12 @@ static void call_terminated(SalOp *op, const char *from){ break; } ms_message("Current call terminated..."); + if (call->refer_pending){ + linphone_core_start_refered_call(lc,call); + } //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) )) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; + linphone_core_stop_ringing(lc); } linphone_call_stop_media_streams(call); if (lc->vtable.show!=NULL) @@ -560,9 +564,10 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de char *msg603=_("Call declined."); const char *msg=details; LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + LinphoneCall *referer=call->referer; if (call==NULL){ - ms_warning("Call faillure reported on already cleaned call ?"); + ms_warning("Call faillure reported on already terminated call."); return ; } @@ -612,55 +617,83 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de if (call->params.media_encryption == LinphoneMediaEncryptionSRTP && !linphone_core_is_media_encryption_mandatory(lc)) { int i; - ms_message("Outgoing call failed with SRTP (SAVP) enabled - retrying with AVP"); + ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call); linphone_call_stop_media_streams(call); - if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress){ + 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; ilocaldesc->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_start_invite(lc, call); + linphone_core_restart_invite(lc, call); + return; } - 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.")); } } - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } - linphone_call_stop_media_streams (call); - if (call->referer && linphone_call_get_state(call->referer)==LinphoneCallPaused && call->referer->was_automatically_paused){ - /*resume to the call that send us the refer automatically*/ - linphone_core_resume_call(lc,call->referer); + /*some call error are not fatal*/ + switch (call->state) { + case LinphoneCallUpdating: + 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); + return; + default: + break; /*nothing to do*/ } + linphone_core_stop_ringing(lc); + linphone_call_stop_media_streams(call); + #ifdef BUILD_UPNP linphone_call_delete_upnp_session(call); #endif //BUILD_UPNP - - if (sr == SalReasonDeclined) { - call->reason=LinphoneReasonDeclined; + + call->reason=linphone_reason_from_sal(sr); + if (sr==SalReasonDeclined){ linphone_call_set_state(call,LinphoneCallEnd,"Call declined."); - } else if (sr == SalReasonNotFound) { - call->reason=LinphoneReasonNotFound; - linphone_call_set_state(call,LinphoneCallError,"User not found."); - } else if (sr == SalReasonBusy) { - call->reason=LinphoneReasonBusy; - linphone_call_set_state(call,LinphoneCallError,"User is busy."); - linphone_core_play_named_tone(lc,LinphoneToneBusy); - } else { - linphone_call_set_state(call,LinphoneCallError,msg); + }else{ + linphone_call_set_state(call,LinphoneCallError,details); + if (sr==SalReasonBusy) + linphone_core_play_named_tone(lc,LinphoneToneBusy); + } + + 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; + } + linphone_core_notify_refer_state(lc,referer,call); } } @@ -671,54 +704,14 @@ static void call_released(SalOp *op){ }else ms_error("call_released() for already destroyed call ?"); } -static void auth_requested(SalOp *h, const char *realm, const char *username){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); - LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username); - LinphoneCall *call=is_a_linphone_call(sal_op_get_user_pointer(h)); - - if (call && call->ping_op==h){ - /*don't request authentication for ping requests. Their purpose is just to get any - * answer to get the Via's received and rport parameters. - */ - ms_message("auth_requested(): ignored for ping request."); - return; - } - - ms_message("auth_requested() for realm=%s, username=%s",realm,username); - - if (ai && ai->works==FALSE && ai->usecount>=3){ - /*case we tried 3 times to authenticate, without success */ - /*Better is to stop (implemeted below in else statement), and retry later*/ - if (ms_time(NULL)-ai->last_use_time>30){ - ai->usecount=0; /*so that we can allow to retry */ - } - } - - if (ai && (ai->works || ai->usecount<3)){ - SalAuthInfo sai; - sai.username=ai->username; - sai.userid=ai->userid; - sai.realm=ai->realm; - sai.password=ai->passwd; - ms_message("auth_requested(): authenticating realm=%s, username=%s",realm,username); - sal_op_authenticate(h,&sai); - ai->usecount++; - ai->last_use_time=ms_time(NULL); - }else{ - if (ai && ai->works==FALSE) { - sal_op_cancel_authentication(h); - } - if (lc->vtable.auth_info_requested) - lc->vtable.auth_info_requested(lc,realm,username); - } -} - -static void auth_success(SalOp *h, const char *realm, const char *username){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); - LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,realm,username); +static void auth_failure(SalOp *op, SalAuthInfo* info) { + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain); if (ai){ - ms_message("%s/%s authentication works.",realm,username); - ai->works=TRUE; + ms_message("%s/%s/%s authentication fails.",info->realm,info->username,info->domain); + } + if (lc->vtable.auth_info_requested) { + lc->vtable.auth_info_requested(lc,info->realm,info->username,info->domain); } } @@ -727,7 +720,7 @@ static void register_success(SalOp *op, bool_t registered){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op); char *msg; - if (cfg->deletion_date!=0){ + if (!cfg || cfg->deletion_date!=0){ ms_message("Registration success for removed proxy config, ignored"); return; } @@ -763,18 +756,21 @@ static void register_failure(SalOp *op, SalError error, SalReason reason, const lc->vtable.display_status(lc,msg); ms_free(msg); } - if (error== SalErrorFailure && reason == SalReasonForbidden) { - linphone_proxy_config_set_error(cfg, LinphoneReasonBadCredentials); - } else if (error == SalErrorNoResponse) { - linphone_proxy_config_set_error(cfg, LinphoneReasonNoResponse); + + linphone_proxy_config_set_error(cfg,linphone_reason_from_sal(reason)); + + if (error== SalErrorFailure + && reason == SalReasonServiceUnavailable + && linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk) { + linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,_("Service unavailable, retrying")); + } else { + linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); } - linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details); - if (error== SalErrorFailure && reason == SalReasonForbidden) { - const char *realm=NULL,*username=NULL; - if (sal_op_get_auth_requested(op,&realm,&username)==0){ - if (lc->vtable.auth_info_requested) - lc->vtable.auth_info_requested(lc,realm,username); - } + if (cfg->publish_op){ + /*prevent publish to be sent now until registration gets successful*/ + sal_op_release(cfg->publish_op); + cfg->publish_op=NULL; + cfg->send_publish=cfg->publish; } } @@ -854,25 +850,25 @@ static void text_received(SalOp *op, const SalMessage *msg){ } } -static void notify(SalOp *op, const char *from, const char *msg){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); - ms_message("get a %s notify from %s",msg,from); - if(lc->vtable.notify_recv) - lc->vtable.notify_recv(lc,call,from,msg); +static void parse_presence_requested(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) { + linphone_notify_parse_presence(op, content_type, content_subtype, body, result); } -static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); - linphone_notify_recv(lc,op,ss,status); +static void convert_presence_to_xml_requested(SalOp *op, SalPresenceModel *presence, const char *contact, char **content) { + linphone_notify_convert_presence_to_xml(op, presence, contact, content); } -static void subscribe_received(SalOp *op, const char *from){ +static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + linphone_notify_recv(lc,op,ss,model); +} + +static void subscribe_presence_received(SalOp *op, const char *from){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); linphone_subscription_new(lc,op,from); } -static void subscribe_closed(SalOp *op, const char *from){ +static void subscribe_presence_closed(SalOp *op, const char *from){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); linphone_subscription_closed(lc,op); } @@ -892,6 +888,80 @@ 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"); + +#ifndef WIN32 + { + // optinal check for files + struct stat st; + if (stat(key_file,&st)) { + ms_warning("No client certificate key found in %s", key_file); + return FALSE; + } + if (stat(chain_file,&st)) { + ms_warning("No client certificate chain found in %s", chain_file); + return FALSE; + } + } +#endif + + sal_certificates_chain_parse_file(sai, chain_file, SAL_CERTIFICATE_RAW_FORMAT_PEM ); + sal_signing_key_parse_file(sai, key_file, ""); + return sai->certificates && sai->key; +} + +static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { + LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username,sai->domain); + if (ai) { + 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; + } +} +static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) { + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); + if (sai->mode == SalAuthModeHttpDigest) { + if (fill_auth_info(lc,sai)) { + return TRUE; + } else { + if (lc->vtable.auth_info_requested) { + lc->vtable.auth_info_requested(lc,sai->realm,sai->username,sai->domain); + if (fill_auth_info(lc,sai)) { + return TRUE; + } + } + return FALSE; + } + } else if (sai->mode == SalAuthModeTls) { + return fill_auth_info_with_client_certificate(lc,sai); + } else { + return FALSE; + } +} + static void notify_refer(SalOp *op, SalReferStatus status){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); @@ -935,6 +1005,7 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus sta 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); @@ -942,15 +1013,101 @@ static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){ chat_msg->state=chatStatusSal2Linphone(status); linphone_chat_message_store_state(chat_msg); if (chat_msg && chat_msg->cb) { + ms_message("Notifying text delivery with status %i",chat_msg->state); chat_msg->cb(chat_msg ,chat_msg->state ,chat_msg->cb_ud); } - linphone_chat_message_destroy(chat_msg); + 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); + } + } +} + +static void info_received(SalOp *op, const SalBody *body){ + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + linphone_core_notify_info_message(lc,op,body); +} + +static void subscribe_response(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); - if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) { - /*op was only create for messaging purpose, destroying*/ - sal_op_release(op); + if (lev==NULL) return; + + if (status==SalSubscribeActive){ + linphone_event_set_state(lev,LinphoneSubscriptionActive); + }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); + } +} + +static void notify(SalOp *op, SalSubscribeStatus st, const char *eventname, const SalBody *body){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + LinphoneContent content; + + if (lev==NULL) { + /*out of subscribe notify */ + lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionOutgoing,eventname); + } + if (lc->vtable.notify_received){ + const LinphoneContent *ct=linphone_content_from_sal_body(&content,body); + if (ct) lc->vtable.notify_received(lc,lev,eventname,ct); + } + if (st!=SalSubscribeNone){ + linphone_event_set_state(lev,linphone_subscription_state_from_sal(st)); + } +} + +static void subscribe_received(SalOp *op, const char *eventname, const SalBody *body){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); + + if (lev==NULL) { + lev=linphone_event_new_with_op(lc,op,LinphoneSubscriptionIncoming,eventname); + linphone_event_set_state(lev,LinphoneSubscriptionIncomingReceived); + }else{ + /*subscribe refresh, unhandled*/ + } + +} + +static void subscribe_closed(SalOp *op){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + + linphone_event_set_state(lev,LinphoneSubscriptionTerminated); +} + +static void on_publish_response(SalOp* op, SalError err, SalReason reason){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + + if (lev==NULL) return; + if (err==SalErrorNone){ + 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); + } +} + +static void on_expire(SalOp *op){ + LinphoneEvent *lev=(LinphoneEvent*)sal_op_get_user_pointer(op); + + if (lev==NULL) return; + + if (linphone_event_get_publish_state(lev)==LinphonePublishOk){ + linphone_event_set_publish_state(lev,LinphonePublishExpiring); } } @@ -963,8 +1120,7 @@ SalCallbacks linphone_sal_callbacks={ call_terminated, call_failure, call_released, - auth_requested, - auth_success, + auth_failure, register_success, register_failure, vfu_request, @@ -972,12 +1128,21 @@ SalCallbacks linphone_sal_callbacks={ refer_received, text_received, text_delivery_update, - notify, - notify_presence, notify_refer, subscribe_received, subscribe_closed, + subscribe_response, + notify, + subscribe_presence_received, + subscribe_presence_closed, + parse_presence_requested, + convert_presence_to_xml_requested, + notify_presence, ping_reply, + auth_requested, + info_received, + on_publish_response, + on_expire }; diff --git a/coreapi/chat.c b/coreapi/chat.c index c12bb3398..c2e6a9cf5 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -31,6 +31,15 @@ * @{ */ +/** + * Returns an array of chat rooms + * @param lc #LinphoneCore object + * @return An array of #LinpĥoneChatRoom +**/ +MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) { + return lc->chatrooms; +} + /** * Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org * @param lc #LinphoneCore object @@ -50,6 +59,32 @@ LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char * } return NULL; } + +bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){ + return linphone_address_weak_equal(cr->peer_url,from); +} + +/** + * Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org if not already existing, else return exisiting one + * @param lc #LinphoneCore object + * @param to destination address for messages + * @return #LinphoneChatRoom where messaging can take place. + */ +LinphoneChatRoom* linphone_core_get_or_create_chat_room(LinphoneCore* lc, const char* to) { + LinphoneAddress *to_addr=linphone_core_interpret_url(lc,to); + LinphoneChatRoom *ret; + + if (to_addr==NULL){ + ms_error("linphone_core_get_or_create_chat_room(): Cannot make a valid address with %s",to); + return NULL; + } + ret=linphone_core_get_chat_room(lc,to_addr); + linphone_address_destroy(to_addr); + if (!ret){ + ret=linphone_core_create_chat_room(lc,to); + } + return ret; +} /** * Destroy a LinphoneChatRoom. @@ -60,16 +95,16 @@ void linphone_chat_room_destroy(LinphoneChatRoom *cr){ lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr); linphone_address_destroy(cr->peer_url); ms_free(cr->peer); + ms_free(cr); } static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg){ - const char *route=NULL; - const char *identity=linphone_core_find_best_identity(cr->lc,cr->peer_url,&route); SalOp *op=NULL; LinphoneCall *call; char* content_type; + const char *identity=NULL; time_t t=time(NULL); if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){ @@ -82,19 +117,20 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM 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)); } } } msg->time=t; 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); - sal_op_set_route(op,route); + 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*/ - if (msg->custom_headers){ - sal_op_set_custom_header(op,msg->custom_headers); - msg->custom_headers=NULL; /*transfered to the SalOp*/ - } } if (msg->external_body_url) { content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url); @@ -105,7 +141,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM } msg->dir=LinphoneChatMessageOutgoing; msg->from=linphone_address_new(identity); - linphone_chat_message_store(msg); + msg->storage_id=linphone_chat_message_store(msg); } /** @@ -118,12 +154,6 @@ void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) { _linphone_chat_room_send_message(cr,linphone_chat_room_create_message(cr,msg)); } -bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){ - if (linphone_address_get_username(cr->peer_url) && linphone_address_get_username(from) && - strcmp(linphone_address_get_username(cr->peer_url),linphone_address_get_username(from))==0) return TRUE; - return FALSE; -} - void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, LinphoneChatMessage *msg){ if (msg->message) //legacy API @@ -181,14 +211,15 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag msg->time=sal_msg->time; msg->state=LinphoneChatMessageStateDelivered; msg->is_read=FALSE; - ch=sal_op_get_custom_header(op); + msg->dir=LinphoneChatMessageIncoming; + ch=sal_op_get_recv_custom_header(op); if (ch) msg->custom_headers=sal_custom_header_clone(ch); if (sal_msg->url) { linphone_chat_message_set_external_body_url(msg, sal_msg->url); } linphone_address_destroy(addr); - linphone_chat_message_store(msg); + msg->storage_id=linphone_chat_message_store(msg); linphone_chat_room_message_received(cr,lc,msg); ms_free(cleanfrom); ms_free(from); @@ -238,6 +269,41 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con return msg; } +/** + * Create a message attached to a dedicated chat room; + * @param cr the chat room. + * @param message text message, NULL if absent. + * @param external_body_url the URL given in external body or NULL. + * @param state the LinphoneChatMessage.State of the message. + * @param time the time_t at which the message has been received/sent. + * @param is_read TRUE if the message should be flagged as read, FALSE otherwise. + * @param is_incoming TRUE if the message has been received, FALSE otherwise. + * @return a new #LinphoneChatMessage + */ +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) { + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + + LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1); + 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; + msg->time=time; + msg->state=state; + msg->is_read=is_read; + if (is_incoming) { + msg->dir=LinphoneChatMessageIncoming; + linphone_chat_message_set_from(msg, linphone_chat_room_get_peer_address(cr)); + linphone_chat_message_set_to(msg, linphone_address_new(linphone_core_get_identity(lc))); + } else { + msg->dir=LinphoneChatMessageOutgoing; + linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr)); + linphone_chat_message_set_from(msg, linphone_address_new(linphone_core_get_identity(lc))); + } + return msg; +} + /** * Send a message to peer member of this chat room. * @param cr #LinphoneChatRoom object @@ -246,7 +312,7 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con * @param ud user data for the status cb. * @note The LinphoneChatMessage must not be destroyed until the the callback is called. */ -void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb, void* ud) { +void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangedCb status_cb, void* ud) { msg->cb=status_cb; msg->cb_ud=ud; msg->state=LinphoneChatMessageStateInProgress; @@ -261,7 +327,7 @@ const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle"; case LinphoneChatMessageStateInProgress:return "LinphoneChatMessageStateInProgress"; case LinphoneChatMessageStateDelivered:return "LinphoneChatMessageStateDelivered"; - case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered"; + case LinphoneChatMessageStateNotDelivered:return "LinphoneChatMessageStateNotDelivered"; default: return "Unknown state"; } @@ -336,6 +402,16 @@ const LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* return message->from; } +/** + * Set destination of the message + *@param message #LinphoneChatMessage obj + *@param to #LinphoneAddress destination of this message (copied) + */ +void linphone_chat_message_set_to(LinphoneChatMessage* message, const LinphoneAddress* to) { + if(message->to) linphone_address_destroy(message->to); + message->to=linphone_address_clone(to); +} + /** * Get destination of the message *@param message #LinphoneChatMessage obj @@ -401,6 +477,31 @@ const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* messag return sal_custom_header_find(message->custom_headers,header_name); } +/** + * Returns TRUE if the message has been read, otherwise returns FALSE. + * @param message the message +**/ +bool_t linphone_chat_message_is_read(LinphoneChatMessage* message) { + return message->is_read; +} + +/** + * Returns TRUE if the message has been sent, returns FALSE if the message has been received. + * @param message the message +**/ +bool_t linphone_chat_message_is_outgoing(LinphoneChatMessage* message) { + return message->dir == LinphoneChatMessageOutgoing; +} + +/** + * Returns the id used to identify this message in the storage database + * @param message the message + * @return the id + */ +unsigned int linphone_chat_message_get_storage_id(LinphoneChatMessage* message) { + return message->storage_id; +} + /** * Duplicate a LinphoneChatMessage **/ @@ -425,6 +526,7 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) new_message->cb=msg->cb; new_message->time=msg->time; new_message->state=msg->state; + new_message->storage_id=msg->storage_id; if (msg->from) new_message->from=linphone_address_clone(msg->from); return new_message; } diff --git a/coreapi/conference.c b/coreapi/conference.c index 0d8ea39a0..53d3edf40 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -218,6 +218,7 @@ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){ static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t active){ int err=0; + char *str; if (!call->current_params.in_conference){ if (call->params.in_conference){ @@ -230,7 +231,7 @@ static int remove_from_conference(LinphoneCore *lc, LinphoneCall *call, bool_t a } call->params.in_conference=FALSE; - char *str=linphone_call_get_remote_address_as_string(call); + str=linphone_call_get_remote_address_as_string(call); ms_message("%s will be removed from conference", str); ms_free(str); if (active){ @@ -289,10 +290,11 @@ static int convert_conference_to_call(LinphoneCore *lc){ * @returns 0 if successful, -1 otherwise. **/ int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){ + int err; char * str=linphone_call_get_remote_address_as_string(call); ms_message("Removing call %s from the conference", str); ms_free(str); - int err=remove_from_conference(lc,call, FALSE); + err=remove_from_conference(lc,call, FALSE); if (err){ ms_error("Error removing participant from conference."); return err; @@ -341,13 +343,14 @@ int linphone_core_leave_conference(LinphoneCore *lc){ * @returns 0 if successful, -1 otherwise **/ int linphone_core_enter_conference(LinphoneCore *lc){ + LinphoneConference *conf; if (linphone_core_sound_resources_locked(lc)) { return -1; } if (lc->current_call != NULL) { _linphone_core_pause_call(lc, lc->current_call); } - LinphoneConference *conf=&lc->conf_ctx; + conf=&lc->conf_ctx; if (conf->local_participant==NULL) add_local_endpoint(conf,lc); return 0; } diff --git a/coreapi/ec-calibrator.c b/coreapi/ec-calibrator.c index fa92b4992..dbb6d857a 100644 --- a/coreapi/ec-calibrator.c +++ b/coreapi/ec-calibrator.c @@ -265,11 +265,13 @@ void ec_calibrator_destroy(EcCalibrator *ecc){ int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, LinphoneEcCalibrationAudioInit audio_init_cb, LinphoneEcCalibrationAudioUninit audio_uninit_cb, void *cb_data){ + unsigned int rate; + if (lc->ecc!=NULL){ ms_error("Echo calibration is still on going !"); return -1; } - unsigned int rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000); + rate = lp_config_get_int(lc->config,"sound","echo_cancellation_rate",8000); lc->ecc=ec_calibrator_new(lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard,rate,cb,audio_init_cb,audio_uninit_cb,cb_data); return 0; } diff --git a/coreapi/event.c b/coreapi/event.c new file mode 100644 index 000000000..46de6b779 --- /dev/null +++ b/coreapi/event.c @@ -0,0 +1,282 @@ +/* +linphone +Copyright (C) 2000 - 2010 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 "private.h" +#include "lpconfig.h" + + +LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatus ss){ + switch(ss){ + case SalSubscribeNone: return LinphoneSubscriptionNone; + case SalSubscribePending: return LinphoneSubscriptionPending; + case SalSubscribeTerminated: return LinphoneSubscriptionTerminated; + case SalSubscribeActive: return LinphoneSubscriptionActive; + } + return LinphoneSubscriptionNone; +} + +const char *linphone_subscription_state_to_string(LinphoneSubscriptionState state){ + switch(state){ + case LinphoneSubscriptionNone: return "LinphoneSubscriptionNone"; + case LinphoneSubscriptionIncomingReceived: return "LinphoneSubscriptionIncomingReceived"; + case LinphoneSubscriptionOutoingInit: return "LinphoneSubscriptionOutoingInit"; + case LinphoneSubscriptionPending: return "LinphoneSubscriptionPending"; + case LinphoneSubscriptionActive: return "LinphoneSubscriptionActive"; + case LinphoneSubscriptionTerminated: return "LinphoneSubscriptionTerminated"; + case LinphoneSubscriptionError: return "LinphoneSubscriptionError"; + } + return NULL; +} + +LINPHONE_PUBLIC const char *linphone_publish_state_to_string(LinphonePublishState state){ + switch(state){ + case LinphonePublishNone: return "LinphonePublishNone"; + case LinphonePublishProgress: return "LinphonePublishProgress"; + case LinphonePublishOk: return "LinphonePublishOk"; + case LinphonePublishError: return "LinphonePublishError"; + case LinphonePublishCleared: return "LinphonePublishCleared"; + case LinphonePublishExpiring: return "LinphonePublishExpiring"; + } + return NULL; +} + +static LinphoneEvent * linphone_event_new_base(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name, SalOp *op){ + LinphoneEvent *lev=ms_new0(LinphoneEvent,1); + lev->lc=lc; + lev->dir=dir; + lev->op=op; + lev->refcnt=1; + lev->name=ms_strdup(name); + sal_op_set_user_pointer(lev->op,lev); + return lev; +} + +LinphoneEvent *linphone_event_new(LinphoneCore *lc, LinphoneSubscriptionDir dir, const char *name){ + LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, sal_op_new(lc->sal)); + return lev; +} + +LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name){ + LinphoneEvent *lev=linphone_event_new_base(lc, dir, name, op); + if (dir==LinphoneSubscriptionIncoming){ + lev->resource_addr=linphone_address_clone((LinphoneAddress*)sal_op_get_to_address(op)); + lev->from=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(lev->op)); + }else{ + lev->resource_addr=linphone_address_clone((LinphoneAddress*)sal_op_get_from_address(op)); + } + return lev; +} + +void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){ + LinphoneCore *lc=lev->lc; + if (lev->subscription_state!=state){ + ms_message("LinphoneEvent [%p] moving to subscription state %s",lev,linphone_subscription_state_to_string(state)); + lev->subscription_state=state; + if (lc->vtable.subscription_state_changed){ + lc->vtable.subscription_state_changed(lev->lc,lev,state); + } + if (state==LinphoneSubscriptionTerminated){ + linphone_event_unref(lev); + } + } +} + +void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState state){ + LinphoneCore *lc=lev->lc; + if (lev->publish_state!=state){ + ms_message("LinphoneEvent [%p] moving to publish state %s",lev,linphone_publish_state_to_string(state)); + lev->publish_state=state; + if (lc->vtable.publish_state_changed){ + lc->vtable.publish_state_changed(lev->lc,lev,state); + } + } +} + +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; +} + +LinphoneReason linphone_event_get_reason(const LinphoneEvent *lev){ + return lev->reason; +} + +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); + return lev; +} + + +int linphone_event_update_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; + } + if (lev->dir!=LinphoneSubscriptionOutgoing){ + ms_error("linphone_event_deny_subscription(): cannot update an incoming subscription."); + return -1; + } + return sal_subscribe(lev->op,NULL,NULL,NULL,-1,sal_body_from_content(&salbody,body)); +} + +int linphone_event_accept_subscription(LinphoneEvent *lev){ + int err; + if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){ + ms_error("linphone_event_accept_subscription(): cannot accept subscription if subscription wasn't just received."); + return -1; + } + err=sal_subscribe_accept(lev->op); + if (err==0){ + linphone_event_set_state(lev,LinphoneSubscriptionActive); + } + return err; +} + +int linphone_event_deny_subscription(LinphoneEvent *lev, LinphoneReason reason){ + int err; + if (lev->subscription_state!=LinphoneSubscriptionIncomingReceived){ + ms_error("linphone_event_deny_subscription(): cannot deny subscription if subscription wasn't just received."); + return -1; + } + err=sal_subscribe_decline(lev->op,linphone_reason_to_sal(reason)); + linphone_event_set_state(lev,LinphoneSubscriptionTerminated); + return err; +} + +int linphone_event_notify(LinphoneEvent *lev, const LinphoneContent *body){ + SalBody salbody; + if (lev->subscription_state!=LinphoneSubscriptionActive){ + ms_error("linphone_event_notify(): cannot notify if subscription is not active."); + return -1; + } + if (lev->dir!=LinphoneSubscriptionIncoming){ + ms_error("linphone_event_notify(): cannot notify if not an incoming subscription."); + return -1; + } + 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){ + 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 (err==0){ + linphone_event_set_publish_state(lev,LinphonePublishProgress); + }else{ + 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; +} + +void linphone_event_set_user_data(LinphoneEvent *ev, void *up){ + ev->userdata=up; +} + +void *linphone_event_get_user_data(const LinphoneEvent *ev){ + return ev->userdata; +} + +void linphone_event_terminate(LinphoneEvent *lev){ + lev->terminating=TRUE; + if (lev->dir==LinphoneSubscriptionIncoming){ + sal_notify_close(lev->op); + }else if (lev->dir==LinphoneSubscriptionOutgoing){ + sal_unsubscribe(lev->op); + } + + if (lev->publish_state!=LinphonePublishNone){ + if (lev->publish_state==LinphonePublishOk){ + sal_publish(lev->op,NULL,NULL,NULL,0,NULL); + } + return; + } + + if (lev->subscription_state!=LinphoneSubscriptionNone){ + linphone_event_set_state(lev,LinphoneSubscriptionTerminated); + return; + } + +} + + +LinphoneEvent *linphone_event_ref(LinphoneEvent *lev){ + lev->refcnt++; + return lev; +} + +static void linphone_event_destroy(LinphoneEvent *lev){ + if (lev->op) + sal_op_release(lev->op); + ms_free(lev->name); + if (lev->resource_addr) linphone_address_destroy(lev->resource_addr); + if (lev->from) linphone_address_destroy(lev->from); + ms_free(lev); +} + +void linphone_event_unref(LinphoneEvent *lev){ + lev->refcnt--; + if (lev->refcnt==0) linphone_event_destroy(lev); +} + +LinphoneSubscriptionDir linphone_event_get_subscription_dir(LinphoneEvent *lev){ + return lev->dir; +} + +LinphoneSubscriptionState linphone_event_get_subscription_state(const LinphoneEvent *lev){ + return lev->subscription_state; +} + +const char *linphone_event_get_name(const LinphoneEvent *lev){ + return lev->name; +} + +const LinphoneAddress *linphone_event_get_from(const LinphoneEvent *lev){ + return lev->from; +} + +const LinphoneAddress *linphone_event_get_resource(const LinphoneEvent *lev){ + return lev->resource_addr; +} + diff --git a/coreapi/event.h b/coreapi/event.h new file mode 100644 index 000000000..9acb94b2d --- /dev/null +++ b/coreapi/event.h @@ -0,0 +1,237 @@ +/* +linphone +Copyright (C) 2000 - 2010 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. +*/ +#ifndef LINPHONEEVENT_H +#define LINPHONEEVENT_H + +/** + * @addtogroup subscriptions + * @{ +**/ + +struct _LinphoneEvent; + +/** + * Object representing an event state, which is subcribed or published. + * @see linphone_core_publish() + * @see linphone_core_subscribe() +**/ +typedef struct _LinphoneEvent LinphoneEvent; + +/** + * Enum for subscription direction (incoming or outgoing). +**/ +enum _LinphoneSubscriptionDir{ + LinphoneSubscriptionIncoming, + LinphoneSubscriptionOutgoing, + LinphoneSubscriptionInvalidDir +}; + +/** + * Typedef alias for _LinphoneSubscriptionDir +**/ +typedef enum _LinphoneSubscriptionDir LinphoneSubscriptionDir; + +/** + * Enum for subscription states. +**/ +enum _LinphoneSubscriptionState{ + LinphoneSubscriptionNone, /**< Initial state, should not be used.**/ + LinphoneSubscriptionOutoingInit, /**refresh_generic_publish property is set to 0.*/ + LinphonePublishCleared /**uri; LinphoneAddress *fb=((LinphoneFriend*)b)->uri; - if (linphone_address_weak_equal (fa,fb)) return 0; + if (linphone_address_weak_equal(fa,fb)) return 0; return 1; } -MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *friend, LinphoneFriend **lf){ +MSList *linphone_find_friend_by_address(MSList *fl, const LinphoneAddress *addr, LinphoneFriend **lf){ MSList *res=NULL; LinphoneFriend dummy; if (lf!=NULL) *lf=NULL; - dummy.uri=(LinphoneAddress*)friend; + dummy.uri=(LinphoneAddress*)addr; res=ms_list_find_custom(fl,friend_compare,&dummy); if (lf!=NULL && res!=NULL) *lf=(LinphoneFriend*)res->data; return res; @@ -97,35 +99,20 @@ LinphoneFriend *linphone_find_friend_by_inc_subscribe(MSList *l, SalOp *op){ LinphoneFriend *linphone_find_friend_by_out_subscribe(MSList *l, SalOp *op){ MSList *elem; + LinphoneFriend *lf; for (elem=l;elem!=NULL;elem=elem->next){ - LinphoneFriend *lf=(LinphoneFriend*)elem->data; + lf=(LinphoneFriend*)elem->data; if (lf->outsub==op) return lf; } return NULL; } void __linphone_friend_do_subscribe(LinphoneFriend *fr){ - char *friend=NULL; - const char *route=NULL; - const char *from=NULL; - const char *fixed_contact=NULL; - LinphoneProxyConfig *cfg; + LinphoneCore *lc=fr->lc; - friend=linphone_address_as_string(fr->uri); - cfg=linphone_core_lookup_known_proxy(fr->lc,linphone_friend_get_address(fr)); - if (cfg!=NULL){ - route=linphone_proxy_config_get_route(cfg); - from=linphone_proxy_config_get_identity(cfg); - if (cfg->op){ - fixed_contact=sal_op_get_contact(cfg->op); - if (fixed_contact) { - ms_message("Contact for subscribe has been fixed using proxy to %s",fixed_contact); - } - } - }else from=linphone_core_get_primary_contact(fr->lc); if (fr->outsub==NULL){ /* people for which we don't have yet an answer should appear as offline */ - fr->status=LinphoneStatusOffline; + fr->presence=NULL; /* if (fr->lc->vtable.notify_recv) fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr); @@ -134,36 +121,42 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){ sal_op_release(fr->outsub); fr->outsub=NULL; } - fr->outsub=sal_op_new(fr->lc->sal); - sal_op_set_route(fr->outsub,route); - sal_op_set_contact(fr->outsub,fixed_contact); - sal_subscribe_presence(fr->outsub,from,friend); + fr->outsub=sal_op_new(lc->sal); + linphone_configure_op(lc,fr->outsub,fr->uri,NULL,TRUE); + sal_subscribe_presence(fr->outsub,NULL,NULL,lp_config_get_int(lc->config,"sip","subscribe_expires",600)); fr->subscribe_active=TRUE; - ms_free(friend); } LinphoneFriend * linphone_friend_new(){ LinphoneFriend *obj=ms_new0(LinphoneFriend,1); obj->pol=LinphoneSPAccept; - obj->status=LinphoneStatusOffline; + obj->presence=NULL; obj->subscribe=TRUE; return obj; } -LinphoneFriend *linphone_friend_new_with_addr(const char *addr){ +LinphoneFriend *linphone_friend_new_with_address(const char *addr){ LinphoneAddress* linphone_address = linphone_address_new(addr); + LinphoneFriend *fr; + if (linphone_address == NULL) { ms_error("Cannot create friend for address [%s]",addr?addr:"null"); return NULL; } - LinphoneFriend *fr=linphone_friend_new(); - if (linphone_friend_set_addr(fr,linphone_address)<0){ - linphone_friend_destroy(fr); - return NULL; - } + fr=linphone_friend_new(); + linphone_friend_set_address(fr,linphone_address); + linphone_address_destroy(linphone_address); return fr; } +void linphone_friend_set_user_data(LinphoneFriend *lf, void *data){ + lf->up=data; +} + +void* linphone_friend_get_user_data(const LinphoneFriend *lf){ + return lf->up; +} + bool_t linphone_friend_in_list(const LinphoneFriend *lf){ return lf->lc!=NULL; } @@ -185,7 +178,7 @@ void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char }else if (lc->default_proxy!=NULL){ /*try adding domain part from default current proxy*/ LinphoneAddress * id=linphone_address_new(linphone_core_get_identity(lc)); - if (id!=NULL){ + if ((id!=NULL) && (uri[0] != '\0')){ linphone_address_set_display_name(id,NULL); linphone_address_set_username(id,uri); *result=linphone_address_as_string(id); @@ -198,14 +191,16 @@ void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char }else{ ms_warning("Fail to interpret friend uri %s",uri); } - }else *result=linphone_address_as_string(fr); - linphone_address_destroy(fr); + }else { + *result=linphone_address_as_string(fr); + linphone_address_destroy(fr); + } } -int linphone_friend_set_addr(LinphoneFriend *lf, const LinphoneAddress *addr){ +int linphone_friend_set_address(LinphoneFriend *lf, const LinphoneAddress *addr){ LinphoneAddress *fr=linphone_address_clone(addr); linphone_address_clean(fr); - if (lf->uri!=NULL) linphone_address_destroy(lf->uri); + if (lf->uri!=NULL) linphone_address_destroy(lf->uri); lf->uri=fr; return 0; } @@ -231,54 +226,12 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri return 0; } -SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){ - switch(os){ - case LinphoneStatusOffline: - return SalPresenceOffline; - break; - case LinphoneStatusOnline: - return SalPresenceOnline; - break; - case LinphoneStatusBusy: - return SalPresenceBusy; - break; - case LinphoneStatusBeRightBack: - return SalPresenceBerightback; - break; - case LinphoneStatusAway: - return SalPresenceAway; - break; - case LinphoneStatusOnThePhone: - return SalPresenceOnthephone; - break; - case LinphoneStatusOutToLunch: - return SalPresenceOuttolunch; - break; - case LinphoneStatusDoNotDisturb: - return SalPresenceDonotdisturb; - break; - case LinphoneStatusMoved: - return SalPresenceMoved; - break; - case LinphoneStatusAltService: - return SalPresenceAltService; - break; - case LinphoneStatusPending: - return SalPresenceOffline; - break; - default: - return SalPresenceOffline; - break; - } - return SalPresenceOffline; -} - -void linphone_friend_notify(LinphoneFriend *lf, LinphoneOnlineStatus os){ +void linphone_friend_notify(LinphoneFriend *lf, LinphonePresenceModel *presence){ char *addr=linphone_address_as_string(linphone_friend_get_address(lf)); ms_message("Want to notify %s, insub=%p",addr,lf->insub); ms_free(addr); if (lf->insub!=NULL){ - sal_notify_presence(lf->insub,linphone_online_status_to_sal(os),NULL); + sal_notify_presence(lf->insub,(SalPresenceModel *)presence); } } @@ -289,10 +242,19 @@ static void linphone_friend_unsubscribe(LinphoneFriend *lf){ } } +static void linphone_friend_invalidate_subscription(LinphoneFriend *lf){ + if (lf->outsub!=NULL) { + sal_op_release(lf->outsub); + lf->outsub=NULL; + lf->subscribe_active=FALSE; + } + lf->initial_subscribes_sent=FALSE; +} + void linphone_friend_close_subscriptions(LinphoneFriend *lf){ linphone_friend_unsubscribe(lf); if (lf->insub){ - sal_notify_close(lf->insub); + sal_notify_presence_close(lf->insub); } } @@ -306,6 +268,7 @@ void linphone_friend_destroy(LinphoneFriend *lf){ sal_op_release(lf->outsub); lf->outsub=NULL; } + if (lf->presence != NULL) linphone_presence_model_unref(lf->presence); if (lf->uri!=NULL) linphone_address_destroy(lf->uri); if (lf->info!=NULL) buddy_info_free(lf->info); ms_free(lf); @@ -315,6 +278,12 @@ const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf){ return lf->uri; } +const char * linphone_friend_get_name(const LinphoneFriend *lf) { + LinphoneAddress *fr = lf->uri; + if (fr == NULL) return NULL; + return linphone_address_get_display_name(fr); +} + bool_t linphone_friend_get_send_subscribe(const LinphoneFriend *lf){ return lf->subscribe; } @@ -324,7 +293,87 @@ LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneF } LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf){ - return lf->status; + LinphoneOnlineStatus online_status = LinphoneStatusOffline; + LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusClosed; + LinphonePresenceActivity *activity = NULL; + unsigned int nb_activities = 0; + + if (lf->presence != NULL) { + basic_status = linphone_presence_model_get_basic_status(lf->presence); + nb_activities = linphone_presence_model_get_nb_activities(lf->presence); + online_status = (basic_status == LinphonePresenceBasicStatusOpen) ? LinphoneStatusOnline : LinphoneStatusOffline; + if (nb_activities > 1) { + char *tmp = NULL; + const LinphoneAddress *addr = linphone_friend_get_address(lf); + if (addr) tmp = linphone_address_as_string(addr); + ms_warning("Friend %s has several activities, get status from the first one", tmp ? tmp : "unknown"); + if (tmp) ms_free(tmp); + nb_activities = 1; + } + if (nb_activities == 1) { + activity = linphone_presence_model_get_activity(lf->presence); + switch (linphone_presence_activity_get_type(activity)) { + case LinphonePresenceActivityBreakfast: + case LinphonePresenceActivityDinner: + case LinphonePresenceActivityLunch: + case LinphonePresenceActivityMeal: + online_status = LinphoneStatusOutToLunch; + break; + case LinphonePresenceActivityAppointment: + case LinphonePresenceActivityMeeting: + case LinphonePresenceActivityPerformance: + case LinphonePresenceActivityPresentation: + case LinphonePresenceActivitySpectator: + case LinphonePresenceActivityWorking: + case LinphonePresenceActivityWorship: + online_status = LinphoneStatusDoNotDisturb; + break; + case LinphonePresenceActivityAway: + case LinphonePresenceActivitySleeping: + online_status = LinphoneStatusAway; + break; + case LinphonePresenceActivityHoliday: + case LinphonePresenceActivityTravel: + case LinphonePresenceActivityVacation: + online_status = LinphoneStatusVacation; + break; + case LinphonePresenceActivityBusy: + case LinphonePresenceActivityLookingForWork: + case LinphonePresenceActivityPlaying: + case LinphonePresenceActivityShopping: + case LinphonePresenceActivityTV: + online_status = LinphoneStatusBusy; + break; + case LinphonePresenceActivityInTransit: + case LinphonePresenceActivitySteering: + online_status = LinphoneStatusBeRightBack; + break; + case LinphonePresenceActivityOnThePhone: + online_status = LinphoneStatusOnThePhone; + break; + case LinphonePresenceActivityOther: + case LinphonePresenceActivityPermanentAbsence: + online_status = LinphoneStatusMoved; + break; + case LinphonePresenceActivityUnknown: + /* Rely on the basic status information. */ + break; + case LinphonePresenceActivityOnline: + /* Should not happen! */ + ms_warning("LinphonePresenceActivityOnline should not happen here!"); + break; + case LinphonePresenceActivityOffline: + online_status = LinphoneStatusOffline; + break; + } + } + } + + return online_status; +} + +const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf) { + return lf->presence; } BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){ @@ -332,27 +381,28 @@ BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf){ } void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ + LinphonePresenceModel *model; + if (fr->uri==NULL) { ms_warning("No sip url defined."); return; } - fr->lc=lc; - + linphone_core_write_friends_config(lc); if (fr->inc_subscribe_pending){ switch(fr->pol){ case LinphoneSPWait: - linphone_friend_notify(fr,LinphoneStatusPending); + model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOther, "Waiting for user acceptance"); + linphone_friend_notify(fr,model); + linphone_presence_model_unref(model); break; case LinphoneSPAccept: if (fr->lc!=NULL) - { - linphone_friend_notify(fr,fr->lc->presence_mode); - } + linphone_friend_notify(fr,fr->lc->presence_model); break; case LinphoneSPDeny: - linphone_friend_notify(fr,LinphoneStatusOffline); + linphone_friend_notify(fr,NULL); break; } fr->inc_subscribe_pending=FALSE; @@ -360,6 +410,8 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){ 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); } ms_message("linphone_friend_apply() done."); lc->bl_refresh=TRUE; @@ -375,6 +427,14 @@ void linphone_friend_done(LinphoneFriend *fr){ linphone_friend_apply(fr,fr->lc); } +LinphoneFriend * linphone_core_create_friend(LinphoneCore *lc) { + return linphone_friend_new(); +} + +LinphoneFriend * linphone_core_create_friend_with_address(LinphoneCore *lc, const char *address) { + return linphone_friend_new_with_address(address); +} + void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) { ms_return_if_fail(lf->lc==NULL); @@ -388,27 +448,57 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf) return ; } lc->friends=ms_list_append(lc->friends,lf); + lf->lc=lc; if ( linphone_core_ready(lc)) linphone_friend_apply(lf,lc); else lf->commit=TRUE; return ; } void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){ - MSList *el=ms_list_find(lc->friends,(void *)fl); + MSList *el=ms_list_find(lc->friends,fl); if (el!=NULL){ linphone_friend_destroy((LinphoneFriend*)el->data); lc->friends=ms_list_remove_link(lc->friends,el); linphone_core_write_friends_config(lc); + }else{ + ms_error("linphone_core_remove_friend(): friend [%p] is not part of core's list.",fl); } } void linphone_core_send_initial_subscribes(LinphoneCore *lc){ 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; - if (f->commit) + 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; + } + } + +} + +void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc){ + const MSList *elem; + for(elem=lc->friends;elem!=NULL;elem=elem->next){ + LinphoneFriend *f=(LinphoneFriend*)elem->data; + linphone_friend_invalidate_subscription(f); + } + lc->initial_subscribes_sent=FALSE; } void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key){ @@ -426,38 +516,22 @@ const char *linphone_friend_get_ref_key(const LinphoneFriend *lf){ return lf->refkey; } -static bool_t username_match(const char *u1, const char *u2){ - if (u1==NULL && u2==NULL) return TRUE; - if (u1 && u2 && strcasecmp(u1,u2)==0) return TRUE; - return FALSE; +LinphoneFriend *linphone_core_find_friend(const LinphoneCore *lc, const LinphoneAddress *addr){ + LinphoneFriend *lf=NULL; + MSList *elem; + for(elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){ + lf=(LinphoneFriend*)elem->data; + if (linphone_address_weak_equal(lf->uri,addr)) + break; + lf=NULL; + } + return lf; } LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *uri){ LinphoneAddress *puri=linphone_address_new(uri); - const MSList *elem; - const char *username; - const char *domain; - LinphoneFriend *lf=NULL; - - if (puri==NULL){ - return NULL; - } - username=linphone_address_get_username(puri); - domain=linphone_address_get_domain(puri); - if (domain==NULL) { - linphone_address_destroy(puri); - return NULL; - } - for(elem=lc->friends;elem!=NULL;elem=ms_list_next(elem)){ - lf=(LinphoneFriend*)elem->data; - const char *it_username=linphone_address_get_username(lf->uri); - const char *it_host=linphone_address_get_domain(lf->uri);; - if (strcasecmp(domain,it_host)==0 && username_match(username,it_username)){ - break; - } - lf=NULL; - } - linphone_address_destroy(puri); + LinphoneFriend *lf=puri ? linphone_core_find_friend(lc,puri) : NULL; + if (puri) linphone_address_unref(puri); return lf; } @@ -511,7 +585,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(LinphoneCore *lc, int inde if (tmp==NULL) { return NULL; } - lf=linphone_friend_new_with_addr(tmp); + lf=linphone_friend_new_with_address(tmp); if (lf==NULL) { return NULL; } diff --git a/coreapi/help/Doxyfile.in b/coreapi/help/Doxyfile.in index 03dbf91a0..27068c53d 100644 --- a/coreapi/help/Doxyfile.in +++ b/coreapi/help/Doxyfile.in @@ -165,7 +165,7 @@ MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- -GENERATE_XML = NO +GENERATE_XML = YES XML_OUTPUT = xml XML_SCHEMA = XML_DTD = @@ -190,7 +190,7 @@ EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = . INCLUDE_FILE_PATTERNS = *.h -PREDEFINED = DOXYGEN +PREDEFINED = DOXYGEN MS2_PUBLIC= LINPHONE_PUBLIC= EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index 902d23c9c..9d35b40a4 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -10,6 +10,7 @@ if HAVE_DOXYGEN # docdir & pkgdocdir are not always defined by automake pkgdocdir=$(docdir)/$(PACKAGE)-$(VERSION) doc_htmldir=$(pkgdocdir)/html +doc_xmldir=$(pkgdocdir)/xml doc_html_DATA = $(top_builddir)/coreapi/help/doc/html/html.tar @@ -20,21 +21,32 @@ $(top_builddir)/coreapi/help/doc/html/index.html: $(SOURCES) Doxyfile Makefile.a rm -rf doc $(DOXYGEN) Doxyfile +doc_xml_DATA = $(top_builddir)/coreapi/help/doc/xml/xml.tar + +$(doc_xml_DATA): $(top_builddir)/coreapi/help/doc/xml/index.xml + cd $(top_builddir)/coreapi/help/doc/xml/ && tar cf xml.tar * + +$(top_builddir)/coreapi/help/doc/xml/index.xml: $(top_builddir)/coreapi/help/doc/html/index.html + + install-data-hook: cd $(DESTDIR)$(doc_htmldir) && tar xf html.tar && rm -f html.tar + cd $(DESTDIR)$(doc_xmldir) && tar xf xml.tar && rm -f xml.tar uninstall-hook: cd $(DESTDIR)$(doc_htmldir) && rm -f * + cd $(DESTDIR)$(doc_xmldir) && rm -f * endif clean-local: rm -rf doc -if ENABLE_TESTS #tutorials -if BUILD_TESTS -noinst_PROGRAMS=helloworld registration buddy_status chatroom + +if ENABLE_TUTORIALS + +noinst_PROGRAMS=helloworld registration buddy_status chatroom notify helloworld_SOURCES=helloworld.c LINPHONE_TUTOS=$(helloworld_SOURCES) @@ -57,17 +69,18 @@ chatroom_SOURCES=chatroom.c LINPHONE_TUTOS+=$(chatroom_SOURCES) chatroom_LDADD=$(helloworld_LDADD) -endif - -endif + +notify_SOURCES=notify.c +LINPHONE_TUTOS+=$(notify_SOURCES) + +notify_LDADD=$(helloworld_LDADD) AM_CFLAGS=\ + -I$(top_srcdir)/coreapi \ $(STRICT_OPTIONS) \ -DIN_LINPHONE \ $(ORTP_CFLAGS) \ - $(OSIP_CFLAGS) \ $(MEDIASTREAMER_CFLAGS) \ - $(EXOSIP_CFLAGS) \ -DENABLE_TRACE \ -DLOG_DOMAIN=\"LinphoneCore\" \ $(IPV6_CFLAGS) \ @@ -78,3 +91,4 @@ AM_CFLAGS=\ tutodir=$(datadir)/tutorials/linphone tuto_DATA=$(LINPHONE_TUTOS) +endif diff --git a/coreapi/help/buddy_status.c b/coreapi/help/buddy_status.c index 6fdb47f40..40db6458e 100644 --- a/coreapi/help/buddy_status.c +++ b/coreapi/help/buddy_status.c @@ -51,12 +51,15 @@ static void stop(int signum){ * presence state change notification callback */ static void notify_presence_recv_updated (LinphoneCore *lc, LinphoneFriend *friend) { + const LinphonePresenceModel* model = linphone_friend_get_presence_model(friend); const LinphoneAddress* friend_address = linphone_friend_get_address(friend); + LinphonePresenceActivity *activity = linphone_presence_model_get_activity(model); + char *activity_str = linphone_presence_activity_to_string(activity); printf("New state state [%s] for user id [%s] \n" - ,linphone_online_status_to_string(linphone_friend_get_status(friend)) + ,activity_str ,linphone_address_as_string (friend_address)); } -static void new_subscription_request (LinphoneCore *lc, LinphoneFriend *friend, const char* url) { +static void new_subscription_requested (LinphoneCore *lc, LinphoneFriend *friend, const char* url) { const LinphoneAddress* friend_address = linphone_friend_get_address(friend); printf(" [%s] wants to see your status, accepting\n" ,linphone_address_as_string (friend_address)); @@ -103,11 +106,11 @@ int main(int argc, char *argv[]){ #endif /* Fill the LinphoneCoreVTable with application callbacks. - All are optional. Here we only use the both notify_presence_recv and new_subscription_request callbacks + All are optional. Here we only use the both notify_presence_received and new_subscription_requested callbacks in order to get notifications about friend status. */ - vtable.notify_presence_recv=notify_presence_recv_updated; - vtable.new_subscription_request=new_subscription_request; + vtable.notify_presence_received=notify_presence_recv_updated; + vtable.new_subscription_requested=new_subscription_requested; vtable.registration_state_changed=registration_state_changed; /*just in case sip proxy is used*/ /* @@ -126,7 +129,7 @@ int main(int argc, char *argv[]){ } LinphoneAuthInfo *info; if (password!=NULL){ - info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL,NULL); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } @@ -152,7 +155,7 @@ int main(int argc, char *argv[]){ LinphoneFriend* my_friend=NULL; if (dest_friend) { - my_friend = linphone_friend_new_with_addr(dest_friend); /*creates friend object from dest*/ + my_friend = linphone_friend_new_with_address(dest_friend); /*creates friend object from dest*/ if (my_friend == NULL) { printf("bad destination uri for friend [%s]\n",dest_friend); goto end; @@ -164,7 +167,8 @@ int main(int argc, char *argv[]){ } - linphone_core_set_presence_info(lc,0,NULL,LinphoneStatusOnline); /*set my status to online*/ + /*set my status to online*/ + linphone_core_set_presence_model(lc, linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL)); /* main loop for receiving notifications and doing background linphone core work: */ while(running){ @@ -172,7 +176,8 @@ int main(int argc, char *argv[]){ ms_usleep(50000); } - linphone_core_set_presence_info(lc,0,NULL,LinphoneStatusOffline); /* change my presence status to offline*/ + /* change my presence status to offline*/ + linphone_core_set_presence_model(lc, linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline, NULL)); linphone_core_iterate(lc); /* just to make sure new status is initiate message is issued */ linphone_friend_edit(my_friend); /* start editing friend */ diff --git a/coreapi/help/doxygen.dox b/coreapi/help/doxygen.dox index 8b2e6b7b9..656f25e09 100644 --- a/coreapi/help/doxygen.dox +++ b/coreapi/help/doxygen.dox @@ -152,7 +152,7 @@ linphone_friend_done(my_friend); /*commit changes triggering an UNSUBSCRIBE mess Publishing presence status -
Local presence status can be changed using function linphone_core_set_presence_info() .New status is propagated to all friends \link linphone_core_add_friend() previously added \endlink to #LinphoneCore. +
Local presence status can be changed using function linphone_core_set_presence_model() .New status is propagated to all friends \link linphone_core_add_friend() previously added \endlink to #LinphoneCore. Handling incoming subscription request
New incoming subscription requests are process according to \link linphone_friend_set_inc_subscribe_policy() the incoming subscription policy state \endlink for subscription initiated by \link linphone_core_add_friend() members of the buddy list. \endlink diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java index dc1341d80..53b9331fb 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java @@ -23,18 +23,23 @@ import org.linphone.core.LinphoneCall; 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.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.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; /** * @@ -156,7 +161,7 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { if (mySipPassword != null) { // create authentication structure from identity and add to linphone - lc.addAuthInfo(lcFactory.createAuthInfo(username, mySipPassword, null)); + lc.addAuthInfo(lcFactory.createAuthInfo(username, mySipPassword, null, domain)); } // create proxy config @@ -241,5 +246,39 @@ public class TutorialBuddyStatus implements LinphoneCoreListener { } + @Override + public void transferState(LinphoneCore lc, LinphoneCall call, + State new_call_state) { + // TODO Auto-generated method stub + + } + + @Override + public void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info) { + // TODO Auto-generated method stub + + } + + @Override + public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, + SubscriptionState state) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyReceived(LinphoneCore lc, LinphoneEvent ev, + String eventName, LinphoneContent content) { + // TODO Auto-generated method stub + + } + + @Override + public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, + PublishState state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java index 024927468..371b9af8e 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java @@ -24,6 +24,7 @@ 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; @@ -31,8 +32,12 @@ import org.linphone.core.LinphoneCore.RegistrationState; 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.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; +import org.linphone.core.PublishState; +import org.linphone.core.SubscriptionState; /** @@ -115,7 +120,7 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa try { // Next step is to create a chat room - LinphoneChatRoom chatRoom = lc.createChatRoom(destinationSipAddress); + LinphoneChatRoom chatRoom = lc.getOrCreateChatRoom(destinationSipAddress); // Send message LinphoneChatMessage chatMessage = chatRoom.createLinphoneChatMessage("Hello world"); @@ -163,5 +168,39 @@ public class TutorialChatRoom implements LinphoneCoreListener, LinphoneChatMessa write("Sent message [" + msg.getText() + "] new state is " + state.toString()); } + @Override + public void transferState(LinphoneCore lc, LinphoneCall call, + State new_call_state) { + // TODO Auto-generated method stub + + } + + @Override + public void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info) { + // TODO Auto-generated method stub + + } + + @Override + public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, + SubscriptionState state) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyReceived(LinphoneCore lc, LinphoneEvent ev, + String eventName, LinphoneContent content) { + // TODO Auto-generated method stub + + } + + @Override + public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, + PublishState state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java index d6b61cf8b..e8ba341ad 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java @@ -23,16 +23,21 @@ import org.linphone.core.LinphoneCall; 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.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.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.PublishState; +import org.linphone.core.SubscriptionState; /** @@ -167,5 +172,39 @@ public class TutorialHelloWorld implements LinphoneCoreListener { } + @Override + public void transferState(LinphoneCore lc, LinphoneCall call, + State new_call_state) { + // TODO Auto-generated method stub + + } + + @Override + public void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info) { + // TODO Auto-generated method stub + + } + + @Override + public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, + SubscriptionState state) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyReceived(LinphoneCore lc, LinphoneEvent ev, + String eventName, LinphoneContent content) { + // TODO Auto-generated method stub + + } + + @Override + public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, + PublishState state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java index fa18d51f8..93aa87d04 100644 --- a/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java +++ b/coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java @@ -23,16 +23,21 @@ import org.linphone.core.LinphoneCall; 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.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.LinphoneInfoMessage; import org.linphone.core.LinphoneProxyConfig; import org.linphone.core.LinphoneCall.State; import org.linphone.core.LinphoneCore.GlobalState; import org.linphone.core.LinphoneCore.RegistrationState; +import org.linphone.core.PublishState; +import org.linphone.core.SubscriptionState; /** @@ -126,7 +131,7 @@ public class TutorialRegistration implements LinphoneCoreListener { if (password != null) { // create authentication structure from identity and add to linphone - lc.addAuthInfo(lcFactory.createAuthInfo(username, password, null)); + lc.addAuthInfo(lcFactory.createAuthInfo(username, password, null, domain)); } // create proxy config @@ -198,6 +203,40 @@ public class TutorialRegistration implements LinphoneCoreListener { } + @Override + public void transferState(LinphoneCore lc, LinphoneCall call, + State new_call_state) { + // TODO Auto-generated method stub + + } + + @Override + public void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info) { + // TODO Auto-generated method stub + + } + + @Override + public void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, + SubscriptionState state) { + // TODO Auto-generated method stub + + } + + @Override + public void notifyReceived(LinphoneCore lc, LinphoneEvent ev, + String eventName, LinphoneContent content) { + // TODO Auto-generated method stub + + } + + @Override + public void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, + PublishState state) { + // TODO Auto-generated method stub + + } + } diff --git a/coreapi/help/notify.c b/coreapi/help/notify.c new file mode 100644 index 000000000..58775b044 --- /dev/null +++ b/coreapi/help/notify.c @@ -0,0 +1,183 @@ + +/* +linphone +Copyright (C) 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. +*/ + +/** + * @defgroup notify_tutorials Generic subscribe/notify example + * @ingroup tutorials + *This program is a _very_ simple usage example of liblinphone. + *It demonstrates how to listen to a SIP subscription. + *It then sends notify requests back periodically. + *first argument must be like sip:jehan@sip.linphone.org , second must be password . + *
+ *ex registration sip:jehan@sip.linphone.org secret + *
Registration is cleared on SIGINT + *
+ *@include registration.c + + * + */ + +#define DEBUG 1 + +#ifdef IN_LINPHONE +#include "linphonecore.h" +#else +#include "linphone/linphonecore.h" +#endif + +#include + +static bool_t running=TRUE; + +static void stop(int signum){ + running=FALSE; +} + +typedef struct MyAppData{ + LinphoneEvent *ev; +}MyAppData; + +/** + * Registration state notification callback + */ +static void registration_state_changed(LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ + printf("New registration state %s for user id [%s] at proxy [%s]\n" + ,linphone_registration_state_to_string(cstate) + ,linphone_proxy_config_get_identity(cfg) + ,linphone_proxy_config_get_addr(cfg)); +} + +static void subscription_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state){ + MyAppData *data=(MyAppData*)linphone_core_get_user_data(lc); + if (state==LinphoneSubscriptionIncomingReceived){ + printf("Receiving new subscription for event %s\n",linphone_event_get_name(ev)); + if (data->ev==NULL) { + linphone_event_accept_subscription(ev); + data->ev=linphone_event_ref(ev); + }else{ + linphone_event_deny_subscription(ev,LinphoneReasonBusy); + } + }else if (state==LinphoneSubscriptionTerminated){ + if (data->ev==ev){ + linphone_event_unref(data->ev); + data->ev=NULL; + } + } +} + +LinphoneCore *lc; +int main(int argc, char *argv[]){ + LinphoneCoreVTable vtable={0}; + MyAppData *data=ms_new0(MyAppData,1); + char* identity=NULL; + char* password=NULL; + int i; + + /* takes sip uri identity from the command line arguments */ + if (argc>1){ + identity=argv[1]; + } + + /* takes password from the command line arguments */ + if (argc>2){ + password=argv[2]; + } + + signal(SIGINT,stop); + +#ifdef DEBUG + linphone_core_enable_logs(NULL); /*enable liblinphone logs.*/ +#endif + /* + Fill the LinphoneCoreVTable with application callbacks. + All are optional. Here we only use the registration_state_changed callbacks + in order to get notifications about the progress of the registration. + */ + vtable.registration_state_changed=registration_state_changed; + vtable.subscription_state_changed=subscription_state_changed; + + /* + Instanciate a LinphoneCore object given the LinphoneCoreVTable + */ + lc=linphone_core_new(&vtable,NULL,NULL,data); + + LinphoneProxyConfig* proxy_cfg; + /*create proxy config*/ + proxy_cfg = linphone_proxy_config_new(); + /*parse identity*/ + LinphoneAddress *from = linphone_address_new(identity); + if (from==NULL){ + printf("%s not a valid sip uri, must be like sip:toto@sip.linphone.org \n",identity); + goto end; + } + LinphoneAuthInfo *info; + if (password!=NULL){ + info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL,NULL); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + } + + // configure proxy entries + linphone_proxy_config_set_identity(proxy_cfg,identity); /*set identity with user name and domain*/ + const char* server_addr = linphone_address_get_domain(from); /*extract domain address from identity*/ + linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); /* we assume domain = proxy server address*/ + linphone_proxy_config_enable_register(proxy_cfg,TRUE); /*activate registration for this proxy config*/ + linphone_address_destroy(from); /*release resource*/ + + linphone_core_add_proxy_config(lc,proxy_cfg); /*add proxy config to linphone core*/ + linphone_core_set_default_proxy(lc,proxy_cfg); /*set to default proxy*/ + + i=0; + /* main loop for receiving notifications and doing background linphonecore work: */ + while(running){ + linphone_core_iterate(lc); /* first iterate initiates registration */ + ms_usleep(50000); + ++i; + if (data->ev && i%100==0){ + LinphoneContent content; + content.type="application"; + content.subtype="goodxml"; + content.data="really cool"; + content.size=strlen((const char*)content.data); + linphone_event_notify(data->ev,&content); + } + } + + linphone_core_get_default_proxy(lc,&proxy_cfg); /* get default proxy config*/ + linphone_proxy_config_edit(proxy_cfg); /*start editing proxy configuration*/ + linphone_proxy_config_enable_register(proxy_cfg,FALSE); /*de-activate registration for this proxy config*/ + linphone_proxy_config_done(proxy_cfg); /*initiate REGISTER with expire = 0*/ + + if (data->ev){ + linphone_event_terminate(data->ev); + } + + while(linphone_proxy_config_get_state(proxy_cfg) != LinphoneRegistrationCleared){ + linphone_core_iterate(lc); /*to make sure we receive call backs before shutting down*/ + ms_usleep(50000); + } + +end: + printf("Shutting down...\n"); + linphone_core_destroy(lc); + ms_free(data); + printf("Exited\n"); + return 0; +} + diff --git a/coreapi/help/registration.c b/coreapi/help/registration.c index 6ed93e70d..70ab4f4ca 100644 --- a/coreapi/help/registration.c +++ b/coreapi/help/registration.c @@ -102,7 +102,7 @@ int main(int argc, char *argv[]){ } LinphoneAuthInfo *info; if (password!=NULL){ - info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new(linphone_address_get_username(from),NULL,password,NULL,NULL,NULL); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ } diff --git a/coreapi/info.c b/coreapi/info.c new file mode 100644 index 000000000..ff7ff3c93 --- /dev/null +++ b/coreapi/info.c @@ -0,0 +1,197 @@ +/*************************************************************************** + * info.c + * + * Thu May 16 11:48:01 2013 + * Copyright 2013 Belledonne Communications SARL + * Author Simon Morlat + * Email simon dot morlat at linphone dot org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "linphonecore.h" +#include "private.h" +#include "lpconfig.h" + + +struct _LinphoneInfoMessage{ + LinphoneContent content; + SalCustomHeader *headers; +}; + +#define SET_STRING(ptr,field,val) \ + if (ptr->field) { \ + ms_free(ptr->field); \ + ptr->field=NULL; \ + } \ + if (val){ \ + ptr->field=ms_strdup(val); \ + } + +static void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref){ + SET_STRING(obj,type,ref->type); + SET_STRING(obj,subtype,ref->subtype); + SET_STRING(obj,encoding,ref->encoding); + if (obj->data) { + ms_free(obj->data); + obj->data=NULL; + } + if (ref->data){ + obj->data=ms_malloc(ref->size+1); + memcpy(obj->data, ref->data, ref->size); + ((char*)obj->data)[ref->size]='\0'; + } + obj->size=ref->size; +} + +void linphone_content_uninit(LinphoneContent * obj){ + if (obj->type) ms_free(obj->type); + if (obj->subtype) ms_free(obj->subtype); + if (obj->data) ms_free(obj->data); + if (obj->encoding) ms_free(obj->encoding); +} + +LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref){ + SET_STRING(obj,type,ref->type); + SET_STRING(obj,subtype,ref->subtype); + SET_STRING(obj,encoding,ref->encoding); + if (obj->data) { + ms_free(obj->data); + obj->data=NULL; + } + if (ref->data){ + obj->data=ms_malloc(ref->size+1); + memcpy(obj->data, ref->data, ref->size); + ((char*)obj->data)[ref->size]='\0'; + } + obj->size=ref->size; + return obj; +} + +const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref){ + if (ref && ref->type){ + obj->type=(char*)ref->type; + obj->subtype=(char*)ref->subtype; + obj->data=(void*)ref->data; + obj->encoding=(char*)ref->encoding; + obj->size=ref->size; + return obj; + } + return NULL; +} + +SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc){ + if (lc && lc->type){ + body->type=lc->type; + body->subtype=lc->subtype; + body->data=lc->data; + body->size=lc->size; + body->encoding=lc->encoding; + return body; + } + return NULL; +} + +/** + * Destroy a LinphoneInfoMessage +**/ +void linphone_info_message_destroy(LinphoneInfoMessage *im){ + linphone_content_uninit(&im->content); + sal_custom_header_free(im->headers); + ms_free(im); +} + + +LinphoneInfoMessage *linphone_info_message_copy(const LinphoneInfoMessage *orig){ + LinphoneInfoMessage *im=ms_new0(LinphoneInfoMessage,1); + linphone_content_copy(&im->content,&orig->content); + if (orig->headers) im->headers=sal_custom_header_clone(orig->headers); + return im; +} + +/** + * Creates an empty info message. + * @param lc the LinphoneCore + * @return a new LinphoneInfoMessage. + * + * The info message can later be filled with information using linphone_info_message_add_header() or linphone_info_message_set_content(), + * and finally sent with linphone_core_send_info_message(). +**/ +LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore *lc){ + LinphoneInfoMessage *im=ms_new0(LinphoneInfoMessage,1); + return im; +} + +/** + * Send a LinphoneInfoMessage through an established call + * @param call the call + * @param info the info message +**/ +int linphone_call_send_info_message(LinphoneCall *call, const LinphoneInfoMessage *info){ + SalBody body; + sal_op_set_sent_custom_header(call->op,info->headers); + return sal_send_info(call->op,NULL, NULL, sal_body_from_content(&body,&info->content)); +} + +/** + * Add a header to an info message to be sent. + * @param im the info message + * @param name the header'name + * @param value the header's value +**/ +void linphone_info_message_add_header(LinphoneInfoMessage *im, const char *name, const char *value){ + im->headers=sal_custom_header_append(im->headers, name, value); +} + +/** + * Obtain a header value from a received info message. + * @param im the info message + * @param name the header'name + * @return the corresponding header's value, or NULL if not exists. +**/ +const char *linphone_info_message_get_header(const LinphoneInfoMessage *im, const char *name){ + return sal_custom_header_find(im->headers,name); +} + +/** + * Assign a content to the info message. + * @param im the linphone info message + * @param content the content described as a #LinphoneContent structure. + * All fields of the LinphoneContent are copied, thus the application can destroy/modify/recycloe the content object freely ater the function returns. +**/ +void linphone_info_message_set_content(LinphoneInfoMessage *im, const LinphoneContent *content){ + linphone_content_copy(&im->content,content); +} + +/** + * Returns the info message's content as a #LinphoneContent structure. +**/ +const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMessage *im){ + return im->content.type ? &im->content : NULL; +} + +void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body){ + LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); + if (call){ + LinphoneInfoMessage *info=ms_new0(LinphoneInfoMessage,1); + info->headers=sal_custom_header_clone(sal_op_get_recv_custom_header(op)); + if (body) linphone_content_copy_from_sal_body(&info->content,body); + if (lc->vtable.info_received) + lc->vtable.info_received(lc,call,info); + linphone_info_message_destroy(info); + } +} diff --git a/coreapi/linphone_tunnel.cc b/coreapi/linphone_tunnel.cc index 079074aa8..151755078 100644 --- a/coreapi/linphone_tunnel.cc +++ b/coreapi/linphone_tunnel.cc @@ -36,6 +36,7 @@ LinphoneTunnel* linphone_core_get_tunnel(LinphoneCore *lc){ struct _LinphoneTunnel { belledonnecomm::TunnelManager *manager; MSList *config_list; + bool_t auto_detect_enabled; }; extern "C" LinphoneTunnel* linphone_core_tunnel_new(LinphoneCore *lc){ @@ -225,6 +226,7 @@ void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel){ } void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled){ + tunnel->auto_detect_enabled = FALSE; lp_config_set_int(config(tunnel),"tunnel","enabled",(int)enabled); bcTunnel(tunnel)->enable(enabled); } @@ -311,9 +313,14 @@ void linphone_tunnel_reconnect(LinphoneTunnel *tunnel){ } void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){ + tunnel->auto_detect_enabled = TRUE; bcTunnel(tunnel)->autoDetect(); } +bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel) { + return tunnel->auto_detect_enabled; +} + static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){ ortp_logv(level,fmt,args); } diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index f02baab54..cff8fc532 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -53,7 +53,7 @@ typedef struct _LinphoneTunnelConfig LinphoneTunnelConfig; /** * Create a new tunnel configuration */ -LinphoneTunnelConfig *linphone_tunnel_config_new(); +LINPHONE_PUBLIC LinphoneTunnelConfig *linphone_tunnel_config_new(); /** * Set address of server. @@ -61,14 +61,14 @@ LinphoneTunnelConfig *linphone_tunnel_config_new(); * @param tunnel configuration object * @param host tunnel server ip address */ -void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *host); +LINPHONE_PUBLIC void linphone_tunnel_config_set_host(LinphoneTunnelConfig *tunnel, const char *host); /** * Get address of server. * * @param tunnel configuration object */ -const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel); /** * Set tls port of server. @@ -76,14 +76,14 @@ const char *linphone_tunnel_config_get_host(const LinphoneTunnelConfig *tunnel); * @param tunnel configuration object * @param port tunnel server tls port, recommended value is 443 */ -void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port); +LINPHONE_PUBLIC void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunnel, int port); /** * Get tls port of server. * * @param tunnel configuration object */ -int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel); /** * Set the remote port on the tunnel server side used to test udp reachability. @@ -91,14 +91,14 @@ int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel); * @param tunnel configuration object * @param remote_udp_mirror_port remote port on the tunnel server side used to test udp reachability, set to -1 to disable the feature */ -void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel, int remote_udp_mirror_port); +LINPHONE_PUBLIC void linphone_tunnel_config_set_remote_udp_mirror_port(LinphoneTunnelConfig *tunnel, int remote_udp_mirror_port); /** * Get the remote port on the tunnel server side used to test udp reachability. * * @param tunnel configuration object */ -int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig *tunnel); /** * Set the udp packet round trip delay in ms for a tunnel configuration. @@ -106,21 +106,21 @@ int linphone_tunnel_config_get_remote_udp_mirror_port(const LinphoneTunnelConfig * @param tunnel configuration object * @param delay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms. */ -void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay); +LINPHONE_PUBLIC void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunnel, int delay); /** * Get the udp packet round trip delay in ms for a tunnel configuration. * * @param tunnel configuration object */ -int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel); /** * Destroy a tunnel configuration * * @param tunnel configuration object */ -void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel); /** * Add tunnel server configuration @@ -128,7 +128,7 @@ void linphone_tunnel_config_destroy(LinphoneTunnelConfig *tunnel); * @param tunnel object * @param tunnel_config object */ -void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config); +LINPHONE_PUBLIC void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config); /** * Remove tunnel server configuration @@ -136,19 +136,19 @@ void linphone_tunnel_add_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tu * @param tunnel object * @param tunnel_config object */ -void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config); +LINPHONE_PUBLIC void linphone_tunnel_remove_server(LinphoneTunnel *tunnel, LinphoneTunnelConfig *tunnel_config); /** * @param tunnel object * returns a string of space separated list of host:port of tunnel server addresses * */ -const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC const MSList *linphone_tunnel_get_servers(LinphoneTunnel *tunnel); /** * @param tunnel object * Removes all tunnel server address previously entered with addServer() **/ -void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel); /** * Sets whether tunneling of SIP and RTP is required. @@ -157,13 +157,19 @@ void linphone_tunnel_clean_servers(LinphoneTunnel *tunnel); * The TunnelManager takes care of refreshing SIP registration when switching on or off the tunneled mode. * **/ -void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled); +LINPHONE_PUBLIC void linphone_tunnel_enable(LinphoneTunnel *tunnel, bool_t enabled); /** * @param tunnel object * Returns a boolean indicating whether tunneled operation is enabled. **/ -bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel); + +/** + * @param tunnel object + * Returns a boolean indicating whether tunnel is connected successfully. +**/ +bool_t linphone_tunnel_connected(LinphoneTunnel *tunnel); /** * @param tunnel object @@ -178,7 +184,7 @@ bool_t linphone_tunnel_connected(LinphoneTunnel *tunnel); * won't be notified promptly that its connection is now zombie, so it is recommended to call this method that will cause * the lost connection to be closed and new connection to be issued. **/ -void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); /** * Start tunnel need detection. @@ -187,7 +193,14 @@ void linphone_tunnel_reconnect(LinphoneTunnel *tunnel); *
In case of success, the tunnel is automatically turned off. Otherwise, if no udp commmunication is feasible, tunnel mode is turned on. *
Call this method each time to run the auto detection algorithm */ -void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); +LINPHONE_PUBLIC void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); + +/** + * Tells whether tunnel auto detection is enabled. + * @param[in] tunnel LinphoneTunnel object. + * @return TRUE if auto detection is enabled, FALSE otherwise. + */ +LINPHONE_PUBLIC bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunnel); /** * Set an optional http proxy to go through when connecting to tunnel server. @@ -197,7 +210,7 @@ void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel); * @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed. * @param password optional http proxy password. Use NULL if not needed. **/ -void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, int port, const char* username,const char* passwd); +LINPHONE_PUBLIC void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, int port, const char* username,const char* passwd); /** * Retrieve optional http proxy configuration previously set with linphone_tunnel_set_http_proxy(). @@ -207,9 +220,9 @@ void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, in * @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed. * @param password optional http proxy password. Use NULL if not needed. **/ -void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd); +LINPHONE_PUBLIC void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd); -void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel*tunnel, const char* username,const char* passwd); +LINPHONE_PUBLIC void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel*tunnel, const char* username,const char* passwd); /** diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index ee0388604..cf05e5e69 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -43,24 +43,34 @@ static MSWebCam *get_nowebcam_device(){ } #endif -static bool_t generate_b64_crypto_key(int key_length, char* key_out) { +static bool_t generate_b64_crypto_key(int key_length, char* key_out, size_t key_out_size) { int b64_size; - uint8_t* tmp = (uint8_t*) malloc(key_length); - if (ortp_crypto_get_random(tmp, key_length)!=0) { + uint8_t* tmp = (uint8_t*) ms_malloc0(key_length); + if (sal_get_random_bytes(tmp, key_length)==NULL) { ms_error("Failed to generate random key"); - free(tmp); + ms_free(tmp); return FALSE; } b64_size = b64_encode((const char*)tmp, key_length, NULL, 0); + if (b64_size == 0) { + ms_error("Failed to get b64 result size"); + ms_free(tmp); + return FALSE; + } + if (b64_size>=key_out_size){ + ms_error("Insufficient room for writing base64 SRTP key"); + ms_free(tmp); + return FALSE; + } + b64_size=b64_encode((const char*)tmp, key_length, key_out, key_out_size); if (b64_size == 0) { ms_error("Failed to b64 encode key"); - free(tmp); + ms_free(tmp); return FALSE; } key_out[b64_size] = '\0'; - b64_encode((const char*)tmp, key_length, key_out, 40); - free(tmp); + ms_free(tmp); return TRUE; } @@ -122,9 +132,10 @@ static void linphone_call_videostream_encryption_changed(void *data, bool_t encr static void linphone_call_audiostream_encryption_changed(void *data, bool_t encrypted) { char status[255]={0}; + LinphoneCall *call; ms_message("Audio stream is %s ", encrypted ? "encrypted" : "not encrypted"); - LinphoneCall *call = (LinphoneCall *)data; + call = (LinphoneCall *)data; call->audiostream_encrypted=encrypted; if (encrypted && call->core->vtable.display_status != NULL) { @@ -186,7 +197,8 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw PayloadType *pt=(PayloadType*)it->data; if (pt->flags & PAYLOAD_TYPE_ENABLED){ if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){ - ms_message("Codec %s/%i eliminated because of audio bandwidth constraint.",pt->mime_type,pt->clock_rate); + ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s", + pt->mime_type,pt->clock_rate,bandwidth_limit); continue; } if (linphone_core_check_payload_type_usability(lc,pt)){ @@ -222,28 +234,34 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * PayloadType *pt; SalMediaDescription *old_md=call->localdesc; int i; - const char *me=linphone_core_get_identity(lc); - LinphoneAddress *addr=linphone_address_new(me); - const char *username=linphone_address_get_username (addr); + const char *me; SalMediaDescription *md=sal_media_description_new(); + LinphoneAddress *addr; bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0); + char* local_ip=call->localip; linphone_core_adapt_to_network(lc,call->ping_time,&call->params); + if (call->dest_proxy) + me=linphone_proxy_config_get_identity(call->dest_proxy); + else + me=linphone_core_get_identity(lc); + addr=linphone_address_new(me); + md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff)); md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff)); md->n_total_streams=(old_md ? old_md->n_total_streams : 1); md->n_active_streams=1; - strncpy(md->addr,call->localip,sizeof(md->addr)); - strncpy(md->username,username,sizeof(md->username)); + strncpy(md->addr,local_ip,sizeof(md->addr)); + strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); if (call->params.down_bw) md->bandwidth=call->params.down_bw; else md->bandwidth=linphone_core_get_download_bandwidth(lc); /*set audio capabilities */ - strncpy(md->streams[0].rtp_addr,call->localip,sizeof(md->streams[0].rtp_addr)); - strncpy(md->streams[0].rtcp_addr,call->localip,sizeof(md->streams[0].rtcp_addr)); + strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr)); + strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr)); md->streams[0].rtp_port=call->audio_port; md->streams[0].rtcp_port=call->audio_port+1; md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? @@ -285,17 +303,18 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * if (md->streams[i].proto == SalProtoRtpSavp) { if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ int j; + ms_message("Keeping same crypto keys."); for(j=0;jstreams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo)); } }else{ md->streams[i].crypto[0].tag = 1; md->streams[i].crypto[0].algo = AES_128_SHA1_80; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key)) + if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key, SAL_SRTP_KEY_SIZE)) md->streams[i].crypto[0].algo = 0; md->streams[i].crypto[1].tag = 2; md->streams[i].crypto[1].algo = AES_128_SHA1_32; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key)) + if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key, SAL_SRTP_KEY_SIZE)) md->streams[i].crypto[1].algo = 0; md->streams[i].crypto[2].algo = 0; } @@ -314,7 +333,10 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * #endif //BUILD_UPNP linphone_address_destroy(addr); call->localdesc=md; - if (old_md) sal_media_description_unref(old_md); + if (old_md){ + call->localdesc_changed=sal_media_description_equals(md,old_md); + sal_media_description_unref(old_md); + } } static int find_port_offset(LinphoneCore *lc, SalStreamType type){ @@ -407,6 +429,7 @@ static int select_random_port(LinphoneCore *lc, SalStreamType type) { static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ int port_offset; int min_port, max_port; + call->magic=linphone_call_magic; call->refcnt=1; call->state=LinphoneCallIdle; @@ -415,7 +438,7 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->media_start_time=0; call->log=linphone_call_log_new(call, from, to); call->owns_call_log=TRUE; - linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone); + linphone_core_get_audio_port_range(call->core, &min_port, &max_port); if (min_port == max_port) { /* Used fixed RTP audio port. */ @@ -466,18 +489,26 @@ static void discover_mtu(LinphoneCore *lc, const char *remote){ } } -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params) -{ - LinphoneCall *call=ms_new0(LinphoneCall,1); - call->dir=LinphoneCallOutgoing; - call->op=sal_op_new(lc->sal); +void linphone_call_create_op(LinphoneCall *call){ + if (call->op) sal_op_release(call->op); + call->op=sal_op_new(call->core->sal); sal_op_set_user_pointer(call->op,call); + if (call->params.referer) + sal_call_set_referer(call->op,call->params.referer->op); + linphone_configure_op(call->core,call->op,call->log->to,call->params.custom_headers,FALSE); + if (call->params.privacy != LinphonePrivacyDefault) + sal_op_set_privacy(call->op,(SalPrivacyMask)call->params.privacy); + /*else privacy might be set by proxy */ +} + +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){ + LinphoneCall *call=ms_new0(LinphoneCall,1); + + call->dir=LinphoneCallOutgoing; call->core=lc; linphone_core_get_local_ip(lc,NULL,call->localip); linphone_call_init_common(call,from,to); _linphone_call_params_copy(&call->params,params); - sal_op_set_custom_header(call->op,call->params.custom_headers); - call->params.custom_headers=NULL; if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { call->ice_session = ice_session_new(); @@ -497,9 +528,10 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr discover_mtu(lc,linphone_address_get_domain (to)); if (params->referer){ - sal_call_set_referer(call->op,params->referer->op); call->referer=linphone_call_ref(params->referer); } + call->dest_proxy=cfg; + linphone_call_create_op(call); return call; } @@ -513,6 +545,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->op=op; call->core=lc; + if (lc->sip_conf.ping_with_options){ #ifdef BUILD_UPNP if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && @@ -526,7 +559,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro from_str=linphone_address_as_string_uri_only(from); sal_op_set_route(call->ping_op,sal_op_get_network_origin(op)); sal_op_set_user_pointer(call->ping_op,call); - sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str); + sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from),from_str); ms_free(from_str); } } @@ -536,6 +569,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_common(call, from, to); call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/ linphone_core_init_default_params(lc, &call->params); + /*set privacy*/ + call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); + md=sal_call_get_remote_media_description(op); call->params.has_video &= !!lc->video_policy.automatically_accept; if (md) { @@ -610,17 +646,13 @@ static void linphone_call_set_terminated(LinphoneCall *call){ } if (ms_list_size(lc->calls)==0) - linphone_core_notify_all_friends(lc,lc->presence_mode); + linphone_core_send_presence(lc,lc->presence_model); linphone_core_conference_check_uninit(lc); if (call->ringing_beep){ linphone_core_stop_dtmf(lc); call->ringing_beep=FALSE; } - if (call->referer){ - linphone_call_unref(call->referer); - call->referer=NULL; - } } void linphone_call_fix_call_parameters(LinphoneCall *call){ @@ -676,6 +708,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const LinphoneCore *lc=call->core; if (call->state!=cstate){ + call->prevstate=call->state; if (call->state==LinphoneCallEnd || call->state==LinphoneCallError){ if (cstate!=LinphoneCallReleased){ ms_warning("Spurious call state change from %s to %s, ignored.",linphone_call_state_to_string(call->state), @@ -683,8 +716,10 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const return; } } + ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state), - linphone_call_state_to_string(cstate)); + linphone_call_state_to_string(cstate)); + if (cstate!=LinphoneCallRefered){ /*LinphoneCallRefered is rather an event, not a state. Indeed it does not change the state of the call (still paused or running)*/ @@ -701,9 +736,16 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const default: break; } - linphone_call_set_terminated (call); + linphone_call_set_terminated(call); } if (cstate == LinphoneCallConnected) { + if (ms_list_size(lc->calls)==1){ + LinphonePresenceModel *model; + /*there were no call, and now there is a call, send an on-the-phone presence notification automatically*/ + model = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL); + linphone_core_send_presence(call->core,model); + linphone_presence_model_unref(model); + } call->log->status=LinphoneCallSuccess; call->media_start_time=time(NULL); } @@ -717,6 +759,15 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const sal_op_release(call->op); call->op=NULL; } + /*it is necessary to reset pointers to other call to prevent circular references that would result in memory never freed.*/ + if (call->referer){ + linphone_call_unref(call->referer); + call->referer=NULL; + } + if (call->transfer_target){ + linphone_call_unref(call->transfer_target); + call->transfer_target=NULL; + } linphone_call_unref(call); } } @@ -724,6 +775,8 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const static void linphone_call_destroy(LinphoneCall *obj) { + ms_message("Call [%p] freed.",obj); + linphone_call_stop_media_streams(obj); #ifdef BUILD_UPNP linphone_call_delete_upnp_session(obj); #endif //BUILD_UPNP @@ -746,12 +799,20 @@ static void linphone_call_destroy(LinphoneCall *obj) if (obj->refer_to){ ms_free(obj->refer_to); } + if (obj->referer){ + linphone_call_unref(obj->referer); + obj->referer=NULL; + } + if (obj->transfer_target){ + linphone_call_unref(obj->transfer_target); + } if (obj->owns_call_log) linphone_call_log_destroy(obj->log); if (obj->auth_token) { ms_free(obj->auth_token); } linphone_call_params_uninit(&obj->params); + linphone_call_params_uninit(&obj->current_params); ms_free(obj); } @@ -787,8 +848,19 @@ void linphone_call_unref(LinphoneCall *obj){ * Returns current parameters associated to the call. **/ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ - if (call->params.record_file) - call->current_params.record_file=call->params.record_file; +#ifdef VIDEO_ENABLED + VideoStream *vstream; +#endif + MS_VIDEO_SIZE_ASSIGN(call->current_params.sent_vsize, UNKNOWN); + MS_VIDEO_SIZE_ASSIGN(call->current_params.recv_vsize, UNKNOWN); +#ifdef VIDEO_ENABLED + vstream = call->videostream; + if (vstream != NULL) { + call->current_params.sent_vsize = video_stream_get_sent_video_size(vstream); + call->current_params.recv_vsize = video_stream_get_received_video_size(vstream); + } +#endif + return &call->current_params; } @@ -826,9 +898,9 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ cp->low_bandwidth=TRUE; } } - cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op); - return cp; } + cp->custom_headers=(SalCustomHeader*)sal_op_get_recv_custom_header(call->op); + return cp; } return NULL; } @@ -902,6 +974,21 @@ const char *linphone_call_get_refer_to(const LinphoneCall *call){ return call->refer_to; } +/** + * Returns the transferer if this call was started automatically as a result of an incoming transfer request. + * The call in which the transfer request was received is returned in this case. +**/ +LinphoneCall *linphone_call_get_transferer_call(const LinphoneCall *call){ + return call->referer; +} + +/** + * When this call has received a transfer request, returns the new call that was automatically created as a result of the transfer. +**/ +LinphoneCall *linphone_call_get_transfer_target_call(const LinphoneCall *call){ + return call->transfer_target; +} + /** * Returns direction of the call (incoming or outgoing). **/ @@ -1035,6 +1122,14 @@ const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallP return cp->video_codec; } +MSVideoSize linphone_call_params_get_sent_video_size(const LinphoneCallParams *cp) { + return cp->sent_vsize; +} + +MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *cp) { + return cp->recv_vsize; +} + /** * @ingroup call_control * Use to know if this call has been configured in low bandwidth mode. @@ -1070,14 +1165,14 @@ bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){ /** * Returns kind of media encryption selected for the call. **/ -enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) { +LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) { return cp->media_encryption; } /** * Set requested media encryption for a call. **/ -void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) { +void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e) { cp->media_encryption = e; } @@ -1120,6 +1215,7 @@ const char *linphone_call_params_get_custom_header(const LinphoneCallParams *par } void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){ + if (ncp==cp) return; memcpy(ncp,cp,sizeof(LinphoneCallParams)); if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file); /* @@ -1128,6 +1224,43 @@ void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParam if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers); } +/** + * @ingroup call_control + * Set requested level of privacy for the call. + * \xmlonly javascript \endxmlonly + * @param params the call parameters to be modified + * @param LinphonePrivacy to configure privacy + * */ +void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) { + params->privacy=privacy; +} + +/** + * @ingroup call_control + * Get requested level of privacy for the call. + * @param params the call parameters + * @return Privacy mode + * */ +LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params) { + return params->privacy; +} + +/** + * @ingroup call_control + * @return string value of LinphonePrivacy enum + **/ +const char* linphone_privacy_to_string(LinphonePrivacy privacy) { + switch(privacy) { + case LinphonePrivacyDefault: return "LinphonePrivacyDefault"; + case LinphonePrivacyUser: return "LinphonePrivacyUser"; + case LinphonePrivacyHeader: return "LinphonePrivacyHeader"; + case LinphonePrivacySession: return "LinphonePrivacySession"; + case LinphonePrivacyId: return "LinphonePrivacyId"; + case LinphonePrivacyNone: return "LinphonePrivacyNone"; + case LinphonePrivacyCritical: return "LinphonePrivacyCritical"; + default: return "Unknown privacy mode"; + } +} /** * Copy existing LinphoneCallParams to a new LinphoneCallParams object. **/ @@ -1260,6 +1393,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); int dscp=linphone_core_get_video_dscp(lc); + const char *display_filter=linphone_core_get_video_display_filter(lc); call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc)); if (dscp!=-1) @@ -1267,8 +1401,8 @@ void linphone_call_init_video_stream(LinphoneCall *call){ video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0)); if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size); - if( lc->video_conf.displaytype != NULL) - video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype); + if (display_filter != NULL) + video_stream_set_display_filter_name(call->videostream,display_filter); video_stream_set_event_callback(call->videostream,video_stream_event_cb, call); if (lc->rtptf){ RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port); @@ -1283,6 +1417,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ } call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1); ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session); + ms_message ("creating new ice video check list [%p] for session [%p]",call->videostream->ms.ice_check_list,call->videostream->ms.session); } call->videostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq); @@ -1341,6 +1476,13 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05); float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0); int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0); + float speed; + float force; + int sustain; + float transmit_thres; + MSFilter *f=NULL; + float floorgain; + int spk_agc; if (!muted) linphone_core_set_mic_gain_db (lc, mic_gain); @@ -1354,12 +1496,11 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute if (st->volsend){ ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal); - float speed=lp_config_get_float(lc->config,"sound","el_speed",-1); + speed=lp_config_get_float(lc->config,"sound","el_speed",-1); thres=lp_config_get_float(lc->config,"sound","el_thres",-1); - float force=lp_config_get_float(lc->config,"sound","el_force",-1); - int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1); - float transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1); - MSFilter *f=NULL; + force=lp_config_get_float(lc->config,"sound","el_force",-1); + sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1); + transmit_thres=lp_config_get_float(lc->config,"sound","el_transmit_thres",-1); f=st->volsend; if (speed==-1) speed=0.03; if (force==-1) force=25; @@ -1377,8 +1518,8 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute } if (st->volrecv){ /* parameters for a limited noise-gate effect, using echo limiter threshold */ - float floorgain = 1/pow(10,(mic_gain)/10); - int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0); + floorgain = 1/pow(10,(mic_gain)/10); + spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0); ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc); ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres); ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain); @@ -1411,6 +1552,9 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m for(elem=desc->payloads;elem!=NULL;elem=elem->next){ PayloadType *pt=(PayloadType*)elem->data; int number; + /* make a copy of the payload type, so that we left the ones from the SalStreamDescription unchanged. + If the SalStreamDescription is freed, this will have no impact on the running streams*/ + pt=payload_type_clone(pt); if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) { if (desc->type==SalAudio){ @@ -1473,6 +1617,7 @@ static bool_t linphone_call_sound_resources_available(LinphoneCall *call){ return !linphone_core_is_in_conference(lc) && (current==NULL || current==call); } + static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned char tag) { int i; for(i=0; icore; int used_pt=-1; char rtcp_tool[128]={0}; + const SalStreamDescription *stream; + MSSndCard *playcard; + MSSndCard *captcard; + bool_t use_ec; + bool_t mute; + const char *playfile; + const char *recfile; + const SalStreamDescription *local_st_desc; + int crypto_idx; + snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); /* look for savp stream first */ - const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc, + stream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpSavp,SalAudio); /* no savp audio stream, use avp */ if (!stream) @@ -1496,13 +1652,12 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna SalProtoRtpAvp,SalAudio); if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){ - MSSndCard *playcard=lc->sound_conf.lsd_card ? + playcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; - MSSndCard *captcard=lc->sound_conf.capt_sndcard; - const char *playfile=lc->play_file; - const char *recfile=lc->rec_file; + captcard=lc->sound_conf.capt_sndcard; + playfile=lc->play_file; + recfile=lc->rec_file; call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt); - bool_t use_ec; if (used_pt!=-1){ call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt); @@ -1546,15 +1701,17 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate); audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc); audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc)); - if (!call->params.in_conference && call->params.record_file) + if (!call->params.in_conference && call->params.record_file){ audio_stream_mixed_record_open(call->audiostream,call->params.record_file); + call->current_params.record_file=ms_strdup(call->params.record_file); + } audio_stream_start_full( call->audiostream, call->audio_profile, stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr, stream->rtp_port, stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr, - linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0, + linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0, used_pt, linphone_core_get_audio_jittcomp(lc), playfile, @@ -1578,9 +1735,9 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna /* valid local tags are > 0 */ if (stream->proto == SalProtoRtpSavp) { - const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc, + local_st_desc=sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp,SalAudio); - int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); + crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); if (crypto_idx >= 0) { audio_stream_enable_srtp( @@ -1596,7 +1753,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna }else call->audiostream_encrypted=FALSE; if (call->params.in_conference){ /*transform the graph to connect it to the conference filter */ - bool_t mute=stream->dir==SalStreamRecvOnly; + mute=stream->dir==SalStreamRecvOnly; linphone_call_add_to_conf(call, mute); } call->current_params.in_conference=call->params.in_conference; @@ -1676,7 +1833,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna video_stream_set_device_rotation(call->videostream, lc->device_rotation); video_stream_start(call->videostream, call->video_profile, rtp_addr, vstream->rtp_port, - rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0, + rtcp_addr, + linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0, used_pt, linphone_core_get_video_jittcomp(lc), cam); video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool); } @@ -1704,7 +1862,6 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){ LinphoneCore *lc=call->core; - LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc); char *cname; bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc); @@ -1752,9 +1909,6 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone; } - /*also reflect the change if the "wished" params, in order to avoid to propose SAVP or video again - * further in the call, for example during pause,resume, conferencing reINVITEs*/ - linphone_call_fix_call_parameters(call); if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed)) { ice_session_start_connectivity_checks(call->ice_session); } @@ -1786,7 +1940,6 @@ void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { SalStreamDescription *old_stream; SalStreamDescription *new_stream; - int i; old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio); new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio); @@ -1801,11 +1954,6 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); call->audiostream_encrypted = FALSE; } - for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { - old_stream->crypto[i].tag = new_stream->crypto[i].tag; - old_stream->crypto[i].algo = new_stream->crypto[i].algo; - strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1); - } } } @@ -1823,11 +1971,6 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag); call->videostream_encrypted = FALSE; } - for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) { - old_stream->crypto[i].tag = new_stream->crypto[i].tag; - old_stream->crypto[i].algo = new_stream->crypto[i].algo; - strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1); - } } } #endif @@ -1892,6 +2035,7 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) { } audio_stream_stop(call->audiostream); call->audiostream=NULL; + call->current_params.audio_codec = NULL; } } @@ -1905,6 +2049,7 @@ void linphone_call_stop_video_stream(LinphoneCall *call) { linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream); video_stream_stop(call->videostream); call->videostream=NULL; + call->current_params.video_codec = NULL; } #endif } @@ -1912,15 +2057,15 @@ void linphone_call_stop_video_stream(LinphoneCall *call) { void linphone_call_stop_media_streams(LinphoneCall *call){ linphone_call_stop_audio_stream(call); linphone_call_stop_video_stream(call); - ms_event_queue_skip(call->core->msevq); + if (call->core->msevq != NULL) { + ms_event_queue_skip(call->core->msevq); + } if (call->audio_profile){ - rtp_profile_clear_all(call->audio_profile); rtp_profile_destroy(call->audio_profile); call->audio_profile=NULL; } if (call->video_profile){ - rtp_profile_clear_all(call->video_profile); rtp_profile_destroy(call->video_profile); call->video_profile=NULL; } @@ -2129,12 +2274,13 @@ void linphone_call_stop_recording(LinphoneCall *call){ * @} **/ -static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){ - call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0; - call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0; - call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0; - call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0; - ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec", +static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *vs){ + call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (media_stream_get_down_bw(as)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (media_stream_get_up_bw(as)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (media_stream_get_down_bw(vs)*1e-3) : 0; + call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (media_stream_get_up_bw(vs)*1e-3) : 0; + ms_message("bandwidth usage for call [%p]: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec", + call, call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth, call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth , call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth, @@ -2256,20 +2402,17 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse int disconnect_timeout = linphone_core_get_nortp_timeout(call->core); bool_t disconnected=FALSE; - if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){ - RtpSession *as=NULL,*vs=NULL; + if ((call->state==LinphoneCallStreamsRunning || call->state==LinphoneCallOutgoingEarlyMedia || call->state==LinphoneCallIncomingEarlyMedia) && one_second_elapsed){ float audio_load=0, video_load=0; if (call->audiostream!=NULL){ - as=call->audiostream->ms.session; if (call->audiostream->ms.ticker) audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker); } if (call->videostream!=NULL){ if (call->videostream->ms.ticker) video_load=ms_ticker_get_average_load(call->videostream->ms.ticker); - vs=call->videostream->ms.session; } - report_bandwidth(call,as,vs); + report_bandwidth(call,(MediaStream*)call->audiostream,(MediaStream*)call->videostream); ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load); } @@ -2375,6 +2518,10 @@ void linphone_call_log_completed(LinphoneCall *call){ call_logs_write_to_config_file(lc); } +/** + * Returns the current transfer state, if a transfer has been initiated from this call. + * @see linphone_core_transfer_call() , linphone_core_transfer_call_to_another() +**/ LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) { return call->transfer_state; } @@ -2382,16 +2529,15 @@ LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) { void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) { if (state != call->transfer_state) { LinphoneCore* lc = call->core; + ms_message("Transfer state for call [%p] changed from [%s] to [%s]",call + ,linphone_call_state_to_string(call->transfer_state) + ,linphone_call_state_to_string(state)); call->transfer_state = state; if (lc->vtable.transfer_state_changed) lc->vtable.transfer_state_changed(lc, call, state); } } -/** - * Returns true if the call is part of the conference. - * @ingroup conferencing -**/ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { return call->params.in_conference; } @@ -2404,16 +2550,17 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call) { * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0. * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0. * - * cx and cy are updated in return in case their coordinates were to excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video. + * cx and cy are updated in return in case their coordinates were too excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video. **/ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) { VideoStream* vstream = call->videostream; if (vstream && vstream->output) { float zoom[3]; + float halfsize; if (zoom_factor < 1) zoom_factor = 1; - float halfsize = 0.5 * 1.0 / zoom_factor; + halfsize = 0.5 * 1.0 / zoom_factor; if ((*cx - halfsize) < 0) *cx = 0 + halfsize; @@ -2431,3 +2578,84 @@ void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, }else ms_warning("Could not apply zoom: video output wasn't activated."); } +#ifndef USE_BELLESIP +static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ +#else +static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ +#endif + LinphoneAddress *ctt=NULL; +#ifdef USE_BELLESIP + LinphoneAddress *ret=NULL; +#else + char* ret; +#endif + const char *localip=call->localip; + + /* first use user's supplied ip address if asked*/ + if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ + ctt=linphone_core_get_primary_contact_parsed(lc); + linphone_address_set_domain(ctt,linphone_core_get_nat_address_resolved(lc)); + #ifdef USE_BELLESIP + ret=ctt; + #else + ret=linphone_address_as_string(ctt); + #endif + } else if (call->op && sal_op_get_contact(call->op)!=NULL){ + /* if already choosed, don't change it */ + return NULL; + } else if (call->ping_op && sal_op_get_contact(call->ping_op)) { + /* if the ping OPTIONS request succeeded use the contact guessed from the + received, rport*/ + ms_message("Contact has been fixed using OPTIONS"/* to %s",guessed*/); +#ifdef USE_BELLESIP + ret=linphone_address_clone(sal_op_get_contact(call->ping_op));; +#else + ret=ms_strdup(sal_op_get_contact(call->ping_op)); +#endif + } else if (dest_proxy && dest_proxy->op && sal_op_get_contact(dest_proxy->op)){ + /*if using a proxy, use the contact address as guessed with the REGISTERs*/ + ms_message("Contact has been fixed using proxy" /*to %s",fixed_contact*/); +#ifdef USE_BELLESIP + ret=linphone_address_clone(sal_op_get_contact(dest_proxy->op)); +#else + ret=ms_strdup(sal_op_get_contact(dest_proxy->op)); +#endif + } else { + ctt=linphone_core_get_primary_contact_parsed(lc); + if (ctt!=NULL){ + /*otherwise use supllied localip*/ + linphone_address_set_domain(ctt,localip); + linphone_address_set_port(ctt,linphone_core_get_sip_port(lc)); + ms_message("Contact has been fixed using local ip"/* to %s",ret*/); +#ifdef USE_BELLESIP + ret=ctt; +#else + ret=linphone_address_as_string_uri_only(ctt); +#endif + } + } +#ifndef USE_BELLESIP + if (ctt) linphone_address_destroy(ctt); +#endif + return ret; + + +} + +void linphone_call_set_contact_op(LinphoneCall* call) { + LinphoneAddress *contact; + + if (call->dest_proxy == NULL) { + /* Try to define the destination proxy if it has not already been done to have a correct contact field in the SIP messages */ + call->dest_proxy = linphone_core_lookup_known_proxy(call->core, call->log->to); + } + + contact=get_fixed_contact(call->core,call,call->dest_proxy); + if (contact){ + SalTransport tport=sal_address_get_transport((SalAddress*)contact); + sal_address_clean((SalAddress*)contact); /* clean out contact_params that come from proxy config*/ + sal_address_set_transport((SalAddress*)contact,tport); + sal_op_set_contact(call->op, contact); + linphone_address_destroy(contact); + } +} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 3c12d2437..5698d2272 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -66,14 +66,20 @@ static void linphone_core_free_hooks(LinphoneCore *lc); #include "enum.h" + const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); static void toggle_video_preview(LinphoneCore *lc, bool_t val); +#ifdef WINAPI_FAMILY_PHONE_APP +#define SOUNDS_PREFIX "Assets/Sounds/" +#else +#define SOUNDS_PREFIX +#endif /* relative path where is stored local ring*/ -#define LOCAL_RING "rings/oldphone.wav" +#define LOCAL_RING SOUNDS_PREFIX "rings/oldphone.wav" /* same for remote ring (ringback)*/ -#define REMOTE_RING "ringback.wav" -#define HOLD_MUSIC "rings/toy-mono.wav" +#define REMOTE_RING SOUNDS_PREFIX "ringback.wav" +#define HOLD_MUSIC SOUNDS_PREFIX "rings/toy-mono.wav" extern SalCallbacks linphone_sal_callbacks; @@ -370,7 +376,7 @@ float linphone_call_log_get_quality(LinphoneCallLog *cl){ /** * return true if video was enabled at the end of the call */ -LinphoneCallStatus linphone_call_log_video_enabled(LinphoneCallLog *cl) { +bool_t linphone_call_log_video_enabled(LinphoneCallLog *cl) { return cl->video_enabled; } /** @} */ @@ -418,6 +424,11 @@ void linphone_core_set_log_file(FILE *file) { void linphone_core_set_log_level(OrtpLogLevel loglevel) { ortp_set_log_level_mask(loglevel); + if (loglevel == 0) { + sal_disable_logs(); + } else { + sal_enable_logs(); + } } /** @@ -433,6 +444,7 @@ void linphone_core_enable_logs(FILE *file){ if (file==NULL) file=stdout; ortp_set_log_file(file); ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); + sal_enable_logs(); } /** @@ -448,6 +460,7 @@ void linphone_core_enable_logs(FILE *file){ void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){ ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); ortp_set_log_handler(logfunc); + sal_enable_logs(); } /** @@ -458,6 +471,7 @@ void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){ **/ void linphone_core_disable_logs(){ ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL); + sal_disable_logs(); } @@ -476,15 +490,20 @@ static void net_config_read (LinphoneCore *lc) tmpstr=lp_config_get_string(lc->config,"net","nat_address",NULL); if (tmpstr!=NULL && (strlen(tmpstr)<1)) tmpstr=NULL; linphone_core_set_nat_address(lc,tmpstr); - tmp=lp_config_get_int(lc->config,"net","firewall_policy",0); - linphone_core_set_firewall_policy(lc,tmp); tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0); lc->net_conf.nat_sdp_only=tmp; tmp=lp_config_get_int(lc->config,"net","mtu",1300); linphone_core_set_mtu(lc,tmp); - tmp=lp_config_get_int(lc->config,"net","download_ptime",0); - linphone_core_set_download_ptime(lc,tmp); + tmp=lp_config_get_int(lc->config,"net","download_ptime",-1); + if (tmp !=-1 && linphone_core_get_download_ptime(lc) !=0) { + /*legacy parameter*/ + linphone_core_set_download_ptime(lc,tmp); + } + tmp = lp_config_get_int(lc->config, "net", "dns_srv_enabled", 1); + linphone_core_enable_dns_srv(lc, tmp); + /* This is to filter out unsupported firewall policies */ + linphone_core_set_firewall_policy(lc, linphone_core_get_firewall_policy(lc)); } static void build_sound_devices_table(LinphoneCore *lc){ @@ -596,16 +615,12 @@ static void sip_config_read(LinphoneCore *lc) LCSipTransports tr; int i,tmp; int ipv6; - int random_port; if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ sal_use_session_timers(lc->sal,200); } sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1)); - sal_use_101(lc->sal,lp_config_get_int(lc->config,"sip","use_101",1)); - sal_reuse_authorization(lc->sal, lp_config_get_int(lc->config,"sip","reuse_authorization",0)); - sal_expire_old_registration_contacts(lc->sal,lp_config_get_int(lc->config,"sip","expire_old_registration_contacts",0)); ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1); if (ipv6==-1){ @@ -618,24 +633,6 @@ static void sip_config_read(LinphoneCore *lc) tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",0); tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",0); - if (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1) - random_port=(0xDFFF&random())+1024; - else random_port=0; - - if (tr.udp_port==0 && tr.tcp_port==0 && tr.tls_port==0){ - tr.udp_port=5060; - } - - if (tr.udp_port>0 && random_port){ - tr.udp_port=random_port; - tr.tls_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ - }else if (tr.tcp_port>0 && random_port){ - tr.tcp_port=random_port; - tr.tls_port=tr.udp_port=0; /*make sure only one transport is active at a time*/ - }else if (tr.tls_port>0 && random_port){ - tr.tls_port=random_port; - tr.udp_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ - } #ifdef __linux sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", "/etc/ssl/certs")); @@ -719,7 +716,6 @@ static void sip_config_read(LinphoneCore *lc) lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0); linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0)); - sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1)); sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0)); } @@ -839,6 +835,13 @@ static codec_desc_t codec_pref_order[]={ static int find_codec_rank(const char *mime, int clock_rate){ int i; + +#ifdef __arm__ + /*hack for opus, that needs to be disabed by default on ARM single processor, otherwise there is no cpu left for video processing*/ + if (strcasecmp(mime,"opus")==0){ + if (ms_get_cpu_count()==1) return RANK_END; + } +#endif for(i=0;codec_pref_order[i].name!=NULL;++i){ if (strcasecmp(codec_pref_order[i].name,mime)==0 && clock_rate==codec_pref_order[i].rate) return i; @@ -941,6 +944,7 @@ static void build_video_devices_table(LinphoneCore *lc){ static void video_config_read(LinphoneCore *lc){ #ifdef VIDEO_ENABLED int capture, display, self_view; + int automatic_video=1; #endif const char *str; #ifdef VIDEO_ENABLED @@ -957,16 +961,16 @@ static void video_config_read(LinphoneCore *lc){ lp_config_get_string(lc->config,"video","size","cif")); #ifdef VIDEO_ENABLED +#if defined(ANDROID) || defined(__ios) + automatic_video=0; +#endif capture=lp_config_get_int(lc->config,"video","capture",1); display=lp_config_get_int(lc->config,"video","display",1); self_view=lp_config_get_int(lc->config,"video","self_view",1); - vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",1); - vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",1); - lc->video_conf.displaytype=lp_config_get_string(lc->config,"video","displaytype",NULL); - if(lc->video_conf.displaytype) - ms_message("we are using a specific display:%s\n",lc->video_conf.displaytype); - - linphone_core_enable_video(lc,capture,display); + vpol.automatically_initiate=lp_config_get_int(lc->config,"video","automatically_initiate",automatic_video); + vpol.automatically_accept=lp_config_get_int(lc->config,"video","automatically_accept",automatic_video); + linphone_core_enable_video_capture(lc, capture); + linphone_core_enable_video_display(lc, display); linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0)); linphone_core_enable_self_view(lc,self_view); linphone_core_set_video_policy(lc,&vpol); @@ -1035,14 +1039,13 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){ /** * Sets maximum available download bandwidth - * - * @ingroup media_parameters - * * This is IP bandwidth, in kbit/s. * This information is used signaled to other parties during * calls (within SDP messages) so that the remote end can have * sufficient knowledge to properly configure its audio & video * codec output bitrate to not overflow available bandwidth. + * + * @ingroup media_parameters * * @param lc the LinphoneCore object * @param bw the bandwidth in kbits/s, 0 for infinite @@ -1054,9 +1057,6 @@ void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){ /** * Sets maximum available upload bandwidth - * - * @ingroup media_parameters - * * This is IP bandwidth, in kbit/s. * This information is used by liblinphone together with remote * side available bandwidth signaled in SDP messages to properly @@ -1064,19 +1064,27 @@ void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw){ * * @param lc the LinphoneCore object * @param bw the bandwidth in kbits/s, 0 for infinite + * @ingroup media_parameters */ void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw){ lc->net_conf.upload_bw=bw; if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","upload_bw",bw); } +void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enable) { + sal_enable_dns_srv(lc->sal, enable); + if (linphone_core_ready(lc)) + lp_config_set_int(lc->config, "net", "dns_srv_enabled", enable ? 1 : 0); +} + +bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc) { + return sal_dns_srv_enabled(lc->sal); +} + /** * Retrieve the maximum available download bandwidth. - * - * @ingroup media_parameters - * * This value was set by linphone_core_set_download_bandwidth(). - * + * @ingroup media_parameters **/ int linphone_core_get_download_bandwidth(const LinphoneCore *lc){ return lc->net_conf.download_bw; @@ -1084,11 +1092,8 @@ int linphone_core_get_download_bandwidth(const LinphoneCore *lc){ /** * Retrieve the maximum available upload bandwidth. - * - * @ingroup media_parameters - * * This value was set by linphone_core_set_upload_bandwidth(). - * + * @ingroup media_parameters **/ int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){ return lc->net_conf.upload_bw; @@ -1146,6 +1151,14 @@ const char * linphone_core_get_version(void){ static void linphone_core_assign_payload_type(LinphoneCore *lc, PayloadType *const_pt, int number, const char *recv_fmtp){ PayloadType *pt; + +#ifdef ANDROID + if (const_pt->channels==2){ + ms_message("Stereo %s codec not supported on this platform.",const_pt->mime_type); + return; + } +#endif + pt=payload_type_clone(const_pt); if (number==-1){ /*look for a free number */ @@ -1204,10 +1217,21 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const lc->vtable.global_state_changed(lc,gstate,message); } } + static void misc_config_read (LinphoneCore *lc) { LpConfig *config=lc->config; + const char *uuid; + lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",15); lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS); + + uuid=lp_config_get_string(config,"misc","uuid",NULL); + if (!uuid){ + char tmp[64]; + sal_create_uuid(lc->sal,tmp,sizeof(tmp)); + lp_config_set_string(config,"misc","uuid",tmp); + }else if (strcmp(uuid,"0")!=0) /*to allow to disable sip.instance*/ + sal_set_uuid(lc->sal, uuid); } @@ -1257,12 +1281,17 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta #endif #ifdef VIDEO_ENABLED +/* we disable H263 on mobiles because this codec only supports CIF family sizes, and number of cameras don't support it. */ +#if !defined(ANDROID) && !defined(__ios) linphone_core_assign_payload_type(lc,&payload_type_h263,34,NULL); - linphone_core_assign_payload_type(lc,&payload_type_theora,97,NULL); linphone_core_assign_payload_type(lc,&payload_type_h263_1998,98,"CIF=1;QCIF=1"); +#endif + linphone_core_assign_payload_type(lc,&payload_type_mp4v,99,"profile-level-id=3"); - linphone_core_assign_payload_type(lc,&payload_type_h264,102,"profile-level-id=428014"); + linphone_core_assign_payload_type(lc,&payload_type_h264,102,"profile-level-id=42801F"); linphone_core_assign_payload_type(lc,&payload_type_vp8,103,NULL); + + linphone_core_assign_payload_type(lc,&payload_type_theora,97,NULL); linphone_core_assign_payload_type(lc,&payload_type_x_snow,-1,NULL); /* due to limited space in SDP, we have to disable this h264 line which is normally no more necessary */ /* linphone_core_assign_payload_type(&payload_type_h264,-1,"packetization-mode=1;profile-level-id=428014");*/ @@ -1289,6 +1318,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); linphone_core_assign_payload_type(lc,&payload_type_opus,-1,"useinbandfec=1; usedtx=1"); + linphone_core_assign_payload_type(lc,&payload_type_isac,-1,NULL); linphone_core_handle_static_payloads(lc); ms_init(); @@ -1298,6 +1328,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta ms_set_global_event_queue(lc->msevq); lc->sal=sal_init(); + sal_set_user_pointer(lc->sal,lc); sal_set_callbacks(lc->sal,&linphone_sal_callbacks); @@ -1312,7 +1343,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta sip_config_read(lc); /* this will start eXosip*/ video_config_read(lc); //autoreplier_config_init(&lc->autoreplier_conf); - lc->presence_mode=LinphoneStatusOnline; + lc->presence_model=linphone_presence_model_new_with_activity(LinphonePresenceActivityOnline, NULL); misc_config_read(lc); ui_config_read(lc); #ifdef TUNNEL_ENABLED @@ -1454,7 +1485,7 @@ static void update_primary_contact(LinphoneCore *lc){ lc->sip_conf.loopback_only=TRUE; }else lc->sip_conf.loopback_only=FALSE; linphone_address_set_domain(url,tmp); - linphone_address_set_port_int(url,linphone_core_get_sip_port (lc)); + linphone_address_set_port(url,linphone_core_get_sip_port (lc)); guessed=linphone_address_as_string(url); lc->sip_conf.guessed_contact=guessed; linphone_address_destroy(url); @@ -1770,23 +1801,27 @@ int linphone_core_get_sip_port(LinphoneCore *lc) return tr->udp_port>0 ? tr->udp_port : (tr->tcp_port > 0 ? tr->tcp_port : tr->tls_port); } +#if !USE_BELLE_SIP static char _ua_name[64]="Linphone"; static char _ua_version[64]=LINPHONE_VERSION; +#endif -#ifdef HAVE_EXOSIP_GET_VERSION +#if HAVE_EXOSIP_GET_VERSION && !USE_BELLESIP extern const char *eXosip_get_version(); #endif static void apply_user_agent(LinphoneCore *lc){ +#if !USE_BELLESIP /*default user agent is handled at sal level*/ char ua_string[256]; snprintf(ua_string,sizeof(ua_string)-1,"%s/%s (eXosip2/%s)",_ua_name,_ua_version, -#ifdef HAVE_EXOSIP_GET_VERSION +#if HAVE_EXOSIP_GET_VERSION eXosip_get_version() #else "unknown" #endif ); if (lc->sal) sal_set_user_agent(lc->sal,ua_string); +#endif } /** @@ -1795,9 +1830,18 @@ static void apply_user_agent(LinphoneCore *lc){ * @ingroup misc **/ void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char *ver){ +#if USE_BELLESIP + char ua_string[256]; + snprintf(ua_string, sizeof(ua_string) - 1, "%s/%s", name, ver); + if (lc->sal) { + sal_set_user_agent(lc->sal, ua_string); + sal_append_stack_string_to_user_agent(lc->sal); + } +#else strncpy(_ua_name,name,sizeof(_ua_name)-1); strncpy(_ua_version,ver,sizeof(_ua_version)); apply_user_agent(lc); +#endif } const char *linphone_core_get_user_agent_name(void){ @@ -1854,10 +1898,19 @@ static int apply_transports(LinphoneCore *lc){ transport_error(lc,"tls",tr->tls_port); } } + apply_user_agent(lc); + return 0; } +/** + * Returns TRUE if given transport type is supported by the library, FALSE otherwise. +**/ +bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp){ + return sal_transport_available(lc->sal,(SalTransport)tp); +} + /** * Sets the ports to be used for each of transport (UDP or TCP) * @@ -1866,16 +1919,47 @@ static int apply_transports(LinphoneCore *lc){ * * @ingroup network_parameters **/ -int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports * tr){ +int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports * tr_config /*config to be saved*/){ + LCSipTransports tr=*tr_config; + int random_port=(0xDFFF&random())+1024; - if (transports_unchanged(tr,&lc->sip_conf.transports)) + if (lp_config_get_int(lc->config,"sip","sip_random_port",0)==1) { + /*legacy random mode*/ + if (tr.udp_port>0){ + tr.udp_port=random_port; + tr.tls_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ + }else if (tr.tcp_port>0){ + tr.tcp_port=random_port; + tr.tls_port=tr.udp_port=0; /*make sure only one transport is active at a time*/ + }else if (tr.tls_port>0){ + tr.tls_port=random_port; + tr.udp_port=tr.tcp_port=0; /*make sure only one transport is active at a time*/ + } else { + tr.udp_port=random_port; + } + } + if (tr.udp_port == LC_SIP_TRANSPORT_RANDOM) { + tr.udp_port=random_port; + } + if (tr.tcp_port == LC_SIP_TRANSPORT_RANDOM) { + tr.tcp_port=random_port; + } + if (tr.tls_port == LC_SIP_TRANSPORT_RANDOM) { + tr.tls_port=random_port+1; + } + + if (tr.udp_port==0 && tr.tcp_port==0 && tr.tls_port==0){ + tr.udp_port=5060; + } + + if (transports_unchanged(&tr,&lc->sip_conf.transports)) return 0; - memcpy(&lc->sip_conf.transports,tr,sizeof(*tr)); + memcpy(&lc->sip_conf.transports,&tr,sizeof(tr)); if (linphone_core_ready(lc)){ - lp_config_set_int(lc->config,"sip","sip_port",tr->udp_port); - lp_config_set_int(lc->config,"sip","sip_tcp_port",tr->tcp_port); - lp_config_set_int(lc->config,"sip","sip_tls_port",tr->tls_port); + lp_config_set_int(lc->config,"sip","sip_port",tr_config->udp_port); + lp_config_set_int(lc->config,"sip","sip_tcp_port",tr_config->tcp_port); + lp_config_set_int(lc->config,"sip","sip_tls_port",tr_config->tls_port); } if (lc->sal==NULL) return 0; @@ -2098,9 +2182,7 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->ringstream && lc->ringstream_autorelease && lc->dmfs_playing_start_time!=0 && (curtime-lc->dmfs_playing_start_time)>5){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - lc->dmfs_playing_start_time=0; + linphone_core_stop_dtmf_stream(lc); } sal_iterate(lc->sal); @@ -2136,7 +2218,7 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_start_invite(lc,call); } if (call->state==LinphoneCallIncomingReceived){ - ms_message("incoming call ringing for %i seconds",elapsed); + if (one_second_elapsed) ms_message("incoming call ringing for %i seconds",elapsed); if (elapsed>lc->sip_conf.inc_timeout){ LinphoneReason decline_reason; ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); @@ -2166,10 +2248,9 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_run_hooks(lc); linphone_core_do_plugin_tasks(lc); - if (lc->initial_subscribes_sent==FALSE && lc->netup_time!=0 && - (curtime-lc->netup_time)>3){ + if (lc->network_reachable && lc->netup_time!=0 && (curtime-lc->netup_time)>3){ + /*not do that immediately, take your time.*/ linphone_core_send_initial_subscribes(lc); - lc->initial_subscribes_sent=TRUE; } if (one_second_elapsed) { @@ -2198,7 +2279,7 @@ void linphone_core_iterate(LinphoneCore *lc){ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url){ enum_lookup_res_t *enumres=NULL; char *enum_domain=NULL; - LinphoneProxyConfig *proxy=lc->default_proxy;; + LinphoneProxyConfig *proxy=lc->default_proxy; char *tmpurl; LinphoneAddress *uri; @@ -2217,8 +2298,8 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) enum_lookup_res_free(enumres); return uri; } - /* check if we have a "sip:" */ - if (strstr(url,"sip:")==NULL){ + /* check if we have a "sip:" or a "sips:" */ + if ( (strstr(url,"sip:")==NULL) && (strstr(url,"sips:")==NULL) ){ /* this doesn't look like a true sip uri */ if (strchr(url,'@')!=NULL){ /* seems like sip: is missing !*/ @@ -2249,10 +2330,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) if (uri!=NULL){ return uri; } - /* else we could not do anything with url given by user, so display an error */ - if (lc->vtable.display_warning!=NULL){ - lc->vtable.display_warning(lc,_("Could not parse given sip address. A sip url usually looks like sip:user@domain")); - } + return NULL; } @@ -2290,13 +2368,16 @@ void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){ if (call->refer_pending){ LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc); LinphoneCall *newcall; - cp->has_video &= !!lc->video_policy.automatically_initiate; + cp->has_video = call->current_params.has_video; /*start the call to refer-target with video enabled if original call had video*/ cp->referer=call; ms_message("Starting new call to refered address %s",call->refer_to); call->refer_pending=FALSE; newcall=linphone_core_invite_with_params(lc,call->refer_to,cp); linphone_call_params_destroy(cp); - if (newcall) linphone_core_notify_refer_state(lc,call,newcall); + if (newcall) { + call->transfer_target=linphone_call_ref(newcall); + linphone_core_notify_refer_state(lc,call,newcall); + } } } @@ -2306,6 +2387,46 @@ void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, L } } +/* returns the ideal route set for making an operation through this proxy. + * The list must be freed as well as the SalAddress content*/ + + /* +* rfc3608 +6.1. Procedures at the UA + + /.../ + For example, some devices will use locally-configured + explicit loose routing to reach a next-hop proxy, and others will use + a default outbound-proxy routing rule. However, for the result to + function, the combination MUST provide valid routing in the local + environment. In general, the service route set is appended to any + locally configured route needed to egress the access proxy chain. + Systems designers must match the service routing policy of their + nodes with the basic SIP routing policy in order to get a workable + system. +*/ + +static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneAddress *dest){ + MSList *ret=NULL; + const char *local_route=linphone_proxy_config_get_route(proxy); + const LinphoneAddress *srv_route=linphone_proxy_config_get_service_route(proxy); + if (local_route){ + ret=ms_list_append(ret,sal_address_new(local_route)); + } + if (srv_route){ + ret=ms_list_append(ret,sal_address_clone((SalAddress*)srv_route)); + } + if (ret==NULL){ + /*if the proxy address matches the domain part of the destination, then use the same transport + * as the one used for registration. This is done by forcing a route to this proxy.*/ + SalAddress *proxy_addr=sal_address_new(linphone_proxy_config_get_addr(proxy)); + if (strcmp(sal_address_get_domain(proxy_addr),linphone_address_get_domain(dest))==0){ + ret=ms_list_append(ret,proxy_addr); + }else sal_address_destroy(proxy_addr); + } + return ret; +} + LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){ const MSList *elem; LinphoneProxyConfig *found_cfg=NULL; @@ -2314,8 +2435,10 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L /*always prefer the default proxy if it is matching the destination uri*/ if (default_cfg){ const char *domain=linphone_proxy_config_get_domain(default_cfg); - if (strcmp(domain,linphone_address_get_domain(uri))==0) - return default_cfg; + if (strcmp(domain,linphone_address_get_domain(uri))==0){ + found_cfg=default_cfg; + goto end; + } } /*otherwise iterate through the other proxy config and return the first matching*/ @@ -2324,71 +2447,25 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L const char *domain=linphone_proxy_config_get_domain(cfg); if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){ found_cfg=cfg; - break; + goto end; } } +end: + if (found_cfg!=NULL && found_cfg!=default_cfg){ + ms_debug("Overriding default proxy setting for this call/message/subscribe operation."); + }else found_cfg=default_cfg; + return found_cfg; } -const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to, const char **route){ +const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to){ LinphoneProxyConfig *cfg=linphone_core_lookup_known_proxy(lc,to); - if (cfg==NULL) - linphone_core_get_default_proxy (lc,&cfg); if (cfg!=NULL){ - if (route) *route=linphone_proxy_config_get_route(cfg); return linphone_proxy_config_get_identity (cfg); } - return linphone_core_get_primary_contact (lc); + return linphone_core_get_primary_contact(lc); } -static char *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , LinphoneProxyConfig *dest_proxy){ - LinphoneAddress *ctt; - const char *localip=call->localip; - - /* first use user's supplied ip address if asked*/ - if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress){ - ctt=linphone_core_get_primary_contact_parsed(lc); - return ms_strdup_printf("sip:%s@%s",linphone_address_get_username(ctt), - linphone_core_get_nat_address_resolved(lc)); - } - - /* if already choosed, don't change it */ - if (call->op && sal_op_get_contact(call->op)!=NULL){ - return NULL; - } - /* if the ping OPTIONS request succeeded use the contact guessed from the - received, rport*/ - if (call->ping_op){ - const char *guessed=sal_op_get_contact(call->ping_op); - if (guessed){ - ms_message("Contact has been fixed using OPTIONS to %s",guessed); - return ms_strdup(guessed); - } - } - - /*if using a proxy, use the contact address as guessed with the REGISTERs*/ - if (dest_proxy && dest_proxy->op){ - const char *fixed_contact=sal_op_get_contact(dest_proxy->op); - if (fixed_contact) { - ms_message("Contact has been fixed using proxy to %s",fixed_contact); - return ms_strdup(fixed_contact); - } - } - - ctt=linphone_core_get_primary_contact_parsed(lc); - - if (ctt!=NULL){ - char *ret; - /*otherwise use supllied localip*/ - linphone_address_set_domain(ctt,localip); - linphone_address_set_port_int(ctt,linphone_core_get_sip_port(lc)); - ret=linphone_address_as_string_uri_only(ctt); - linphone_address_destroy(ctt); - ms_message("Contact has been fixed using local ip to %s",ret); - return ret; - } - return NULL; -} int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){ bool_t ice_ready = FALSE; @@ -2421,24 +2498,32 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c return 0; } +int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call){ + linphone_call_create_op(call); + return linphone_core_start_invite(lc,call); +} + int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){ int err; - char *contact; char *real_url,*barmsg; char *from; - LinphoneProxyConfig *dest_proxy=call->dest_proxy; - /*try to be best-effort in giving real local or routable contact address */ - contact=get_fixed_contact(lc,call,dest_proxy); - if (contact){ - sal_op_set_contact(call->op, contact); - ms_free(contact); - } + linphone_call_set_contact_op(call); + linphone_core_stop_dtmf_stream(lc); linphone_call_init_media_streams(call); - if (lc->ringstream==NULL) - audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); linphone_call_make_local_media_description(lc,call); + + if (lc->ringstream==NULL) { + if (lc->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard){ + /*give a chance a set card prefered sampling frequency*/ + if (call->localdesc->streams[0].max_rate>0) { + ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate); + } + audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); + } + } + if (!lc->sip_conf.sdp_200_ack){ call->media_pending=TRUE; sal_call_set_local_media_description(call->op,call->localdesc); @@ -2539,6 +2624,46 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr return call; } +static void linphone_transfer_routes_to_op(MSList *routes, SalOp *op){ + MSList *it; + for(it=routes;it!=NULL;it=it->next){ + SalAddress *addr=(SalAddress*)it->data; + sal_op_add_route_address(op,addr); + sal_address_destroy(addr); + } + ms_list_free(routes); +} + +void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact){ + MSList *routes=NULL; + LinphoneProxyConfig *proxy=linphone_core_lookup_known_proxy(lc,dest); + const char *identity; + if (proxy){ + identity=linphone_proxy_config_get_identity(proxy); + if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) { + sal_op_set_privacy(op,linphone_proxy_config_get_privacy(proxy)); + } + }else identity=linphone_core_get_primary_contact(lc); + /*sending out of calls*/ + if (proxy){ + routes=make_routes_for_proxy(proxy,dest); + linphone_transfer_routes_to_op(routes,op); + } + sal_op_set_to_address(op,dest); + sal_op_set_from(op,identity); + sal_op_set_sent_custom_header(op,headers); + if (with_contact && proxy && proxy->op){ + const SalAddress *contact; + if ((contact=sal_op_get_contact(proxy->op))){ + SalTransport tport=sal_address_get_transport((SalAddress*)contact); + SalAddress *new_contact=sal_address_clone(contact); + sal_address_clean(new_contact); /* clean out contact_params that come from proxy config*/ + sal_address_set_transport(new_contact,tport); + sal_op_set_contact(op,new_contact); + sal_address_destroy(new_contact); + } + } +} /** * Initiates an outgoing call given a destination LinphoneAddress @@ -2557,9 +2682,8 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr **/ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params) { - const char *route=NULL; const char *from=NULL; - LinphoneProxyConfig *proxy=NULL,*dest_proxy=NULL; + LinphoneProxyConfig *proxy=NULL; LinphoneAddress *parsed_url2=NULL; char *real_url=NULL; LinphoneCall *call; @@ -2573,19 +2697,11 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const return NULL; } linphone_core_get_default_proxy(lc,&proxy); - route=linphone_core_get_route(lc); real_url=linphone_address_as_string(addr); - dest_proxy=linphone_core_lookup_known_proxy(lc,addr); + proxy=linphone_core_lookup_known_proxy(lc,addr); - if (proxy!=dest_proxy && dest_proxy!=NULL) { - ms_message("Overriding default proxy setting for this call:"); - ms_message("The used identity will be %s",linphone_proxy_config_get_identity(dest_proxy)); - } - - if (dest_proxy!=NULL) - from=linphone_proxy_config_get_identity(dest_proxy); - else if (proxy!=NULL) + if (proxy!=NULL) from=linphone_proxy_config_get_identity(proxy); /* if no proxy or no identity defined for this proxy, default to primary contact*/ @@ -2593,16 +2709,15 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const parsed_url2=linphone_address_new(from); - call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params); - call->dest_proxy=dest_proxy; - sal_op_set_route(call->op,route); - + call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params,proxy); + if(linphone_core_add_call(lc,call)!= 0) { ms_warning("we had a problem in adding the call into the invite ... weird"); linphone_call_unref(call); return NULL; } + /* this call becomes now the current one*/ lc->current_call=call; linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); @@ -2661,6 +2776,10 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const * @ingroup call_control * The remote endpoint is expected to issue a new call to the specified destination. * The current call remains active and thus can be later paused or terminated. + * + * It is possible to follow the progress of the transfer provided that transferee sends notification about it. + * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. **/ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url) { @@ -2697,6 +2816,10 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char * This method will send a transfer request to the transfered person. The phone of the transfered is then * expected to automatically call to the destination of the transfer. The receiver of the transfer will then automatically * close the call with us (the 'dest' call). + * + * It is possible to follow the progress of the transfer provided that transferee sends notification about it. + * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. **/ int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){ int result = sal_call_refer_with_replaces (call->op,dest->op); @@ -2742,6 +2865,8 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (md){ if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ sal_call_decline(call->op,SalReasonMedia,NULL); + linphone_call_stop_media_streams(call); + linphone_core_del_call(lc,call); linphone_call_unref(call); return; } @@ -2761,9 +2886,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (ms_list_size(lc->calls)==1){ lc->current_call=call; if (lc->ringstream && lc->dmfs_playing_start_time!=0){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - lc->dmfs_playing_start_time=0; + linphone_core_stop_dtmf_stream(lc); } if (lc->sound_conf.ring_sndcard!=NULL){ if(lc->ringstream==NULL && lc->sound_conf.local_ring){ @@ -2785,6 +2908,8 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); if (call->state==LinphoneCallIncomingReceived){ + /*try to be best-effort in giving real local or routable contact address for 100Rel case*/ + linphone_call_set_contact_op(call); sal_call_notify_ringing(call->op,propose_early_media || ringback_tone!=NULL); if (propose_early_media || ringback_tone!=NULL){ @@ -2956,8 +3081,10 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) sal_call_set_local_media_description(call->op,call->localdesc); sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); - if (md && !sal_media_description_empty(md)) + if (md && !sal_media_description_empty(md)){ linphone_core_update_streams (lc,call,md); + linphone_call_fix_call_parameters(call); + } linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); return 0; } @@ -3004,7 +3131,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const if (params==NULL){ call->params.has_video=lc->video_policy.automatically_accept || call->current_params.has_video; }else - call->params=*params; + _linphone_call_params_copy(&call->params,params); if (call->params.has_video && !linphone_core_video_enabled(lc)){ ms_warning("linphone_core_accept_call_update(): requested video but video support is globally disabled. Refusing video."); @@ -3085,8 +3212,6 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call){ **/ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params) { - LinphoneProxyConfig *cfg=NULL; - const char *contact=NULL; SalOp *replaced; SalMediaDescription *new_md; bool_t was_ringing=FALSE; @@ -3122,9 +3247,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, /*stop ringing */ if (lc->ringstream!=NULL) { ms_message("stop ringing"); - ring_stop(lc->ringstream); - ms_message("ring stopped"); - lc->ringstream=NULL; + linphone_core_stop_ringing(lc); was_ringing=TRUE; } if (call->ringing_beep){ @@ -3132,19 +3255,8 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, call->ringing_beep=FALSE; } - linphone_core_get_default_proxy(lc,&cfg); - call->dest_proxy=cfg; - call->dest_proxy=linphone_core_lookup_known_proxy(lc,call->log->to); - - if (cfg!=call->dest_proxy && call->dest_proxy!=NULL) { - ms_message("Overriding default proxy setting for this call:"); - ms_message("The used identity will be %s",linphone_proxy_config_get_identity(call->dest_proxy)); - } - /*try to be best-effort in giving real local or routable contact address*/ - contact=get_fixed_contact(lc,call,call->dest_proxy); - if (contact) - sal_op_set_contact(call->op,contact); - + /*try to be best-effort in giving real local or routable contact address */ + linphone_call_set_contact_op(call); if (params){ const SalMediaDescription *md = sal_call_get_remote_media_description(call->op); _linphone_call_params_copy(&call->params,params); @@ -3158,6 +3270,16 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, if (call->audiostream==NULL) linphone_call_init_media_streams(call); + + /*give a chance a set card prefered sampling frequency*/ + if (call->localdesc->streams[0].max_rate>0) { + ms_message ("configuring prefered card sampling rate to [%i]",call->localdesc->streams[0].max_rate); + if (lc->sound_conf.play_sndcard) + ms_snd_card_set_preferred_sample_rate(lc->sound_conf.play_sndcard, call->localdesc->streams[0].max_rate); + if (lc->sound_conf.capt_sndcard) + ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate); + } + if (!was_ringing && call->audiostream->ms.ticker==NULL){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } @@ -3182,10 +3304,7 @@ int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *e sal_call_terminate(call->op); /*stop ringing*/ - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); linphone_call_stop_media_streams(call); #ifdef BUILD_UPNP @@ -3204,10 +3323,7 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ call->reason=LinphoneReasonDeclined; } /*stop ringing*/ - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } + linphone_core_stop_ringing(lc); linphone_call_stop_media_streams(call); @@ -3256,7 +3372,24 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) { call = the_call; } - sal_call_terminate(call->op); + switch (call->state) { + case LinphoneCallReleased: + case LinphoneCallEnd: + ms_warning("No need to terminate a call [%p] in state [%s]",call,linphone_call_state_to_string(call->state)); + return -1; + case LinphoneCallIncomingReceived: + case LinphoneCallIncomingEarlyMedia: + return linphone_core_decline_call(lc,call,LinphoneReasonDeclined); + case LinphoneCallOutgoingInit: { + /* In state OutgoingInit, op has to be destroyed */ + sal_op_release(call->op); + call->op = NULL; + break; + } + default: + sal_call_terminate(call->op); + break; + } terminate_call(lc,call); return 0; } @@ -3271,24 +3404,12 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) * @param reason the reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy **/ int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason){ - SalReason sal_reason=SalReasonUnknown; if (call->state!=LinphoneCallIncomingReceived && call->state!=LinphoneCallIncomingEarlyMedia){ ms_error("linphone_core_decline_call(): Cannot decline a call that is in state %s",linphone_call_state_to_string(call->state)); return -1; } - switch(reason){ - case LinphoneReasonDeclined: - sal_reason=SalReasonDeclined; - break; - case LinphoneReasonBusy: - sal_reason=SalReasonBusy; - break; - default: - ms_error("linphone_core_decline_call(): unsupported reason %s",linphone_reason_to_string(reason)); - return -1; - break; - } - sal_call_decline(call->op,sal_reason,NULL); + + sal_call_decline(call->op,linphone_reason_to_sal(reason),NULL); terminate_call(lc,call); return 0; } @@ -3414,18 +3535,19 @@ int linphone_core_pause_all_calls(LinphoneCore *lc){ void linphone_core_preempt_sound_resources(LinphoneCore *lc){ LinphoneCall *current_call; + if (linphone_core_is_in_conference(lc)){ linphone_core_leave_conference(lc); return; } + current_call=linphone_core_get_current_call(lc); if(current_call != NULL){ ms_message("Pausing automatically the current call."); _linphone_core_pause_call(lc,current_call); } if (lc->ringstream){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; + linphone_core_stop_ringing(lc); } } @@ -3445,6 +3567,10 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) return -1; } if (call->params.in_conference==FALSE){ + if (linphone_core_sound_resources_locked(lc)){ + ms_warning("Cannot resume call %p because another call is locking the sound resources.",the_call); + return -1; + } linphone_core_preempt_sound_resources(lc); ms_message("Resuming call %p",call); } @@ -3468,7 +3594,9 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *the_call) if(sal_call_update(call->op,subject) != 0){ return -1; } - linphone_call_set_state (call,LinphoneCallResuming,"Resuming"); + linphone_call_set_state(call,LinphoneCallResuming,"Resuming"); + if (call->params.in_conference==FALSE) + lc->current_call=call; snprintf(temp,sizeof(temp)-1,"Resuming the call with %s",linphone_call_get_remote_address_as_string(call)); if (lc->vtable.display_status) lc->vtable.display_status(lc,temp); @@ -3496,12 +3624,12 @@ LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const c } int linphone_core_send_publish(LinphoneCore *lc, - LinphoneOnlineStatus presence_mode) + LinphonePresenceModel *presence) { const MSList *elem; for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=ms_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; - if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence_mode); + if (cfg->publish) linphone_proxy_config_send_publish(cfg,presence); } return 0; } @@ -3570,31 +3698,128 @@ void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds){ lc->sip_conf.delayed_timeout=seconds; } -void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away, - const char *contact, - LinphoneOnlineStatus presence_mode) -{ +void linphone_core_set_presence_info(LinphoneCore *lc, int minutes_away, const char *contact, LinphoneOnlineStatus os) { + LinphonePresenceModel *presence = NULL; + char *description = NULL; + LinphonePresenceActivityType acttype = LinphonePresenceActivityUnknown; + if (minutes_away>0) lc->minutes_away=minutes_away; - if (lc->alt_contact!=NULL) { - ms_free(lc->alt_contact); - lc->alt_contact=NULL; + switch (os) { + case LinphoneStatusOffline: + acttype = LinphonePresenceActivityOffline; + break; + case LinphoneStatusOnline: + acttype = LinphonePresenceActivityOnline; + break; + case LinphoneStatusBusy: + acttype = LinphonePresenceActivityBusy; + break; + case LinphoneStatusBeRightBack: + acttype = LinphonePresenceActivityInTransit; + break; + case LinphoneStatusAway: + acttype = LinphonePresenceActivityAway; + break; + case LinphoneStatusOnThePhone: + acttype = LinphonePresenceActivityOnThePhone; + break; + case LinphoneStatusOutToLunch: + acttype = LinphonePresenceActivityLunch; + break; + case LinphoneStatusDoNotDisturb: + acttype = LinphonePresenceActivityBusy; + description = "Do not disturb"; + break; + case LinphoneStatusMoved: + acttype = LinphonePresenceActivityPermanentAbsence; + break; + case LinphoneStatusAltService: + acttype = LinphonePresenceActivityBusy; + description = "Using another messaging service"; + break; + case LinphoneStatusPending: + acttype = LinphonePresenceActivityOther; + description = "Waiting for user acceptance"; + break; + case LinphoneStatusVacation: + acttype = LinphonePresenceActivityVacation; + break; + case LinphoneStatusEnd: + ms_warning("Invalid status LinphoneStatusEnd"); + return; } - if (contact) lc->alt_contact=ms_strdup(contact); - if (lc->presence_mode!=presence_mode){ - linphone_core_notify_all_friends(lc,presence_mode); - /* - Improve the use of all LINPHONE_STATUS available. - !TODO Do not mix "presence status" with "answer status code".. - Use correct parameter to follow sip_if_match/sip_etag. - */ - linphone_core_send_publish(lc,presence_mode); + presence = linphone_presence_model_new_with_activity(acttype, description); + linphone_presence_model_set_contact(presence, contact); + linphone_core_set_presence_model(lc, presence); +} + +void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence){ + linphone_core_notify_all_friends(lc,presence); + linphone_core_send_publish(lc,presence); +} + +void linphone_core_set_presence_model(LinphoneCore *lc, LinphonePresenceModel *presence) { + linphone_core_send_presence(lc,presence); + + if ((lc->presence_model != NULL) && (lc->presence_model != presence)) { + linphone_presence_model_unref(lc->presence_model); + lc->presence_model = presence; } - lc->presence_mode=presence_mode; } LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc){ - return lc->presence_mode; + LinphonePresenceActivity *activity = NULL; + const char *description = NULL; + + activity = linphone_presence_model_get_activity(lc->presence_model); + description = linphone_presence_activity_get_description(activity); + switch (linphone_presence_activity_get_type(activity)) { + case LinphonePresenceActivityOffline: + return LinphoneStatusOffline; + case LinphonePresenceActivityOnline: + return LinphoneStatusOnline; + case LinphonePresenceActivityBusy: + if (description != NULL) { + if (strcmp(description, "Do not disturb") == 0) + return LinphoneStatusDoNotDisturb; + else if (strcmp(description, "Using another messaging service") == 0) + return LinphoneStatusAltService; + } + return LinphoneStatusBusy; + case LinphonePresenceActivityInTransit: + case LinphonePresenceActivitySteering: + return LinphoneStatusBeRightBack; + case LinphonePresenceActivityAway: + return LinphoneStatusAway; + case LinphonePresenceActivityOnThePhone: + return LinphoneStatusOnThePhone; + case LinphonePresenceActivityBreakfast: + case LinphonePresenceActivityDinner: + case LinphonePresenceActivityLunch: + case LinphonePresenceActivityMeal: + return LinphoneStatusOutToLunch; + case LinphonePresenceActivityPermanentAbsence: + return LinphoneStatusMoved; + case LinphonePresenceActivityOther: + if (description != NULL) { + if (strcmp(description, "Waiting for user acceptance") == 0) + return LinphoneStatusPending; + } + return LinphoneStatusBusy; + case LinphonePresenceActivityVacation: + return LinphoneStatusVacation; + case LinphonePresenceActivityAppointment: + case LinphonePresenceActivityMeeting: + case LinphonePresenceActivityWorship: + return LinphoneStatusDoNotDisturb; + default: + return LinphoneStatusBusy; + } +} + +LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc) { + return lc->presence_model; } /** @@ -3658,7 +3883,7 @@ void linphone_core_set_mic_gain_db (LinphoneCore *lc, float gaindb){ ms_message("linphone_core_set_mic_gain_db(): no active call."); return; } - if (st->volrecv){ + if (st->volsend){ ms_filter_call_method(st->volsend,MS_VOLUME_SET_DB_GAIN,&gain); }else ms_warning("Could not apply gain: gain control wasn't activated."); } @@ -3891,12 +4116,6 @@ const char** linphone_core_get_video_devices(const LinphoneCore *lc){ return lc->video_conf.cams; } -/** - * Update detection of sound devices. - * - * Use this function when the application is notified of USB plug events, so that - * list of available hardwares for sound playback and capture is updated. - **/ void linphone_core_reload_sound_devices(LinphoneCore *lc){ const char *ringer,*playback,*capture; ringer=linphone_core_get_ringer_device(lc); @@ -3909,12 +4128,6 @@ void linphone_core_reload_sound_devices(LinphoneCore *lc){ linphone_core_set_capture_device(lc,capture); } -/** - * Update detection of camera devices. - * - * Use this function when the application is notified of USB plug events, so that - * list of available hardwares for video capture is updated. - **/ void linphone_core_reload_video_devices(LinphoneCore *lc){ const char *devid; devid=linphone_core_get_video_device(lc); @@ -4087,11 +4300,6 @@ bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc){ return lc->sound_conf.ea; } -/** - * Mutes or unmutes the local microphone. - * - * @ingroup media_parameters -**/ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ LinphoneCall *call=linphone_core_get_current_call(lc); AudioStream *st=NULL; @@ -4114,9 +4322,7 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ } } -/** - * Returns whether microphone is muted. -**/ + bool_t linphone_core_is_mic_muted(LinphoneCore *lc) { LinphoneCall *call=linphone_core_get_current_call(lc); if (linphone_core_is_in_conference(lc)){ @@ -4128,13 +4334,21 @@ bool_t linphone_core_is_mic_muted(LinphoneCore *lc) { return call->audio_muted; } +void linphone_core_enable_mic(LinphoneCore *lc, bool_t enable) { + linphone_core_mute_mic(lc, (enable == TRUE) ? FALSE : TRUE); +} + +bool_t linphone_core_mic_enabled(LinphoneCore *lc) { + return (linphone_core_is_mic_muted(lc) == TRUE) ? FALSE : TRUE; +} + // returns rtp transmission status for an active stream // if audio is muted and config parameter rtp_no_xmit_on_audio_mute // was set on then rtp transmission is also muted bool_t linphone_core_is_rtp_muted(LinphoneCore *lc){ LinphoneCall *call=linphone_core_get_current_call(lc); if (call==NULL){ - ms_warning("linphone_core_is_mic_muted(): No current call !"); + ms_warning("linphone_core_is_rtp_muted(): No current call !"); return FALSE; } if( linphone_core_get_rtp_no_xmit_on_audio_mute(lc)){ @@ -4191,6 +4405,17 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){ if (server) lc->net_conf.stun_server=ms_strdup(server); else lc->net_conf.stun_server=NULL; + + /* each time the stun server is changed, we must clean the resolved cached addrinfo*/ + if (lc->net_conf.stun_addrinfo){ + freeaddrinfo(lc->net_conf.stun_addrinfo); + lc->net_conf.stun_addrinfo=NULL; + } + /*if a stun server is set, we must request asynchronous resolution immediately to be ready for call*/ + if (lc->net_conf.stun_server){ + linphone_core_resolve_stun_server(lc); + } + if (linphone_core_ready(lc)) lp_config_set_string(lc->config,"net","stun_server",lc->net_conf.stun_server); } @@ -4199,6 +4424,7 @@ const char * linphone_core_get_stun_server(const LinphoneCore *lc){ return lc->net_conf.stun_server; } + bool_t linphone_core_upnp_available(){ #ifdef BUILD_UPNP return TRUE; @@ -4224,21 +4450,6 @@ const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc){ } -const char * linphone_core_get_relay_addr(const LinphoneCore *lc){ - return lc->net_conf.relay; -} - -int linphone_core_set_relay_addr(LinphoneCore *lc, const char *addr){ - if (lc->net_conf.relay!=NULL){ - ms_free(lc->net_conf.relay); - lc->net_conf.relay=NULL; - } - if (addr){ - lc->net_conf.relay=ms_strdup(addr); - } - return 0; -} - void linphone_core_set_nat_address(LinphoneCore *lc, const char *addr) { if (lc->net_conf.nat_address!=NULL){ @@ -4262,7 +4473,7 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc) if (lc->net_conf.nat_address==NULL) return NULL; - if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len)<0) { + if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len, 5060)<0) { return lc->net_conf.nat_address; } @@ -4280,13 +4491,32 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc) } void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol){ -#ifndef BUILD_UPNP - if(pol == LinphonePolicyUseUpnp) { - ms_warning("UPNP is not available, reset firewall policy to no firewall"); - pol = LinphonePolicyNoFirewall; - } + const char *policy = "none"; + + switch (pol) { + default: + case LinphonePolicyNoFirewall: + policy = "none"; + break; + case LinphonePolicyUseNatAddress: + policy = "nat_address"; + break; + case LinphonePolicyUseStun: + policy = "stun"; + break; + case LinphonePolicyUseIce: + policy = "ice"; + break; + case LinphonePolicyUseUpnp: +#ifdef BUILD_UPNP + policy = "upnp"; +#else + ms_warning("UPNP is not available, reset firewall policy to no firewall"); + pol = LinphonePolicyNoFirewall; + policy = "none"; #endif //BUILD_UPNP - lc->net_conf.firewall_policy=pol; + break; + } #ifdef BUILD_UPNP if(pol == LinphonePolicyUseUpnp) { if(lc->upnp == NULL) { @@ -4300,13 +4530,38 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy } linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); #endif //BUILD_UPNP + switch(pol) { + case LinphonePolicyUseUpnp: + sal_nat_helper_enable(lc->sal, FALSE); + sal_enable_auto_contacts(lc->sal,FALSE); + sal_use_rport(lc->sal, FALSE); + break; + default: + sal_nat_helper_enable(lc->sal, lp_config_get_int(lc->config,"net","enable_nat_helper",1)); + sal_enable_auto_contacts(lc->sal,TRUE); + sal_use_rport(lc->sal, lp_config_get_int(lc->config,"sip","use_rport",1)); + break; + } if (lc->sip_conf.contact) update_primary_contact(lc); if (linphone_core_ready(lc)) - lp_config_set_int(lc->config,"net","firewall_policy",pol); + lp_config_set_string(lc->config,"net","firewall_policy",policy); } LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc){ - return lc->net_conf.firewall_policy; + const char *policy = lp_config_get_string(lc->config, "net", "firewall_policy", NULL); + + if ((policy == NULL) || (strcmp(policy, "0") == 0)) + return LinphonePolicyNoFirewall; + else if ((strcmp(policy, "nat_address") == 0) || (strcmp(policy, "1") == 0)) + return LinphonePolicyUseNatAddress; + else if ((strcmp(policy, "stun") == 0) || (strcmp(policy, "2") == 0)) + return LinphonePolicyUseStun; + else if ((strcmp(policy, "ice") == 0) || (strcmp(policy, "3") == 0)) + return LinphonePolicyUseIce; + else if ((strcmp(policy, "upnp") == 0) || (strcmp(policy, "4") == 0)) + return LinphonePolicyUseUpnp; + else + return LinphonePolicyNoFirewall; } /** @@ -4330,27 +4585,14 @@ void linphone_core_clear_call_logs(LinphoneCore *lc){ call_logs_write_to_config_file(lc); } -/** - * Returns number of missed calls. - * Once checked, this counter can be reset with linphone_core_reset_missed_calls_count(). -**/ int linphone_core_get_missed_calls_count(LinphoneCore *lc) { return lc->missed_calls; } -/** - * Resets the counter of missed calls. -**/ void linphone_core_reset_missed_calls_count(LinphoneCore *lc) { lc->missed_calls=0; } -/** - * Remove a specific call log from call history list. - * This function destroys the call log object. It must not be accessed anymore by the application after calling this function. - * @param lc the linphone core object - * @param a LinphoneCallLog object. -**/ void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *cl){ lc->call_logs = ms_list_remove(lc->call_logs, cl); call_logs_write_to_config_file(lc); @@ -4361,10 +4603,11 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val){ #ifdef VIDEO_ENABLED if (val){ if (lc->previewstream==NULL){ + const char *display_filter=linphone_core_get_video_display_filter(lc); lc->previewstream=video_preview_new(); video_preview_set_size(lc->previewstream,lc->video_conf.vsize); - if (lc->video_conf.displaytype) - video_preview_set_display_filter_name(lc->previewstream,lc->video_conf.displaytype); + if (display_filter) + video_preview_set_display_filter_name(lc->previewstream,display_filter); if (lc->preview_window_id!=0) video_preview_set_native_window_id(lc->previewstream,lc->preview_window_id); video_preview_start(lc->previewstream,lc->video_conf.device); @@ -4378,37 +4621,6 @@ static void toggle_video_preview(LinphoneCore *lc, bool_t val){ #endif } -/** - * Enables video globally. - * - * @ingroup media_parameters - * This function does not have any effect during calls. It just indicates LinphoneCore to - * initiate future calls with video or not. The two boolean parameters indicate in which - * direction video is enabled. Setting both to false disables video entirely. - * - * @param lc The LinphoneCore object - * @param vcap_enabled indicates whether video capture is enabled - * @param display_enabled indicates whether video display should be shown - * -**/ -void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled){ -#ifndef VIDEO_ENABLED - if (vcap_enabled || display_enabled) - ms_warning("This version of linphone was built without video support."); -#endif - lc->video_conf.capture=vcap_enabled; - lc->video_conf.display=display_enabled; - if (linphone_core_ready(lc)){ - lp_config_set_int(lc->config,"video","display",lc->video_conf.display); - lp_config_set_int(lc->config,"video","capture",lc->video_conf.capture); - } - /* need to re-apply network bandwidth settings*/ - linphone_core_set_download_bandwidth(lc, - linphone_core_get_download_bandwidth(lc)); - linphone_core_set_upload_bandwidth(lc, - linphone_core_get_upload_bandwidth(lc)); -} - bool_t linphone_core_video_supported(LinphoneCore *lc){ #ifdef VIDEO_ENABLED return TRUE; @@ -4417,14 +4629,56 @@ bool_t linphone_core_video_supported(LinphoneCore *lc){ #endif } -/** - * Returns TRUE if video is enabled, FALSE otherwise. - * @ingroup media_parameters -**/ +void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled) { + linphone_core_enable_video_capture(lc, vcap_enabled); + linphone_core_enable_video_display(lc, display_enabled); +} + bool_t linphone_core_video_enabled(LinphoneCore *lc){ return (lc->video_conf.display || lc->video_conf.capture); } +static void reapply_network_bandwidth_settings(LinphoneCore *lc) { + linphone_core_set_download_bandwidth(lc, linphone_core_get_download_bandwidth(lc)); + linphone_core_set_upload_bandwidth(lc, linphone_core_get_upload_bandwidth(lc)); +} + +void linphone_core_enable_video_capture(LinphoneCore *lc, bool_t enable) { +#ifndef VIDEO_ENABLED + if (enable == TRUE) { + ms_warning("Cannot enable video capture, this version of linphone was built without video support."); + } +#endif + lc->video_conf.capture = enable; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config, "video", "capture", lc->video_conf.capture); + } + /* Need to re-apply network bandwidth settings. */ + reapply_network_bandwidth_settings(lc); +} + +void linphone_core_enable_video_display(LinphoneCore *lc, bool_t enable) { +#ifndef VIDEO_ENABLED + if (enable == TRUE) { + ms_warning("Cannot enable video display, this version of linphone was built without video support."); + } +#endif + lc->video_conf.display = enable; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config, "video", "display", lc->video_conf.display); + } + /* Need to re-apply network bandwidth settings. */ + reapply_network_bandwidth_settings(lc); +} + +bool_t linphone_core_video_capture_enabled(LinphoneCore *lc) { + return lc->video_conf.capture; +} + +bool_t linphone_core_video_display_enabled(LinphoneCore *lc) { + return lc->video_conf.display; +} + /** * Sets the default policy for video. * This policy defines whether: @@ -4482,6 +4736,9 @@ void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){ #ifdef VIDEO_ENABLED LinphoneCall *call=linphone_core_get_current_call (lc); lc->video_conf.selfview=val; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc)); + } if (call && call->videostream){ video_stream_enable_self_view(call->videostream,val); } @@ -4639,26 +4896,60 @@ float linphone_core_get_static_picture_fps(LinphoneCore *lc) { * @ingroup media_parameters **/ unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){ + if (lc->video_window_id) { + /* case where the video id was previously set by the app*/ + return lc->video_window_id; + }else{ #ifdef VIDEO_ENABLED - LinphoneCall *call=linphone_core_get_current_call (lc); - if (call && call->videostream) - return video_stream_get_native_window_id(call->videostream); - if (lc->previewstream) - return video_stream_get_native_window_id(lc->previewstream); + /*case where it was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only)*/ + LinphoneCall *call=linphone_core_get_current_call (lc); + if (call && call->videostream) + return video_stream_get_native_window_id(call->videostream); #endif - return lc->video_window_id; + } + return 0; } -/**@ingroup media_parameters +/* unsets the video id for all calls (indeed it may be kept by filters or videostream object itself by paused calls)*/ +static void unset_video_window_id(LinphoneCore *lc, bool_t preview, unsigned long id){ +#ifdef VIDEO_ENABLED + LinphoneCall *call; + MSList *elem; +#endif + + if (id!=0 && id!=-1) { + ms_error("Invalid use of unset_video_window_id()"); + return; + } +#ifdef VIDEO_ENABLED + for(elem=lc->calls;elem!=NULL;elem=elem->next){ + call=(LinphoneCall *) elem->data; + if (call->videostream){ + if (preview) + video_stream_set_native_preview_window_id(call->videostream,id); + else + video_stream_set_native_window_id(call->videostream,id); + } + } +#endif +} + +/** + * @ingroup media_parameters * Set the native video window id where the video is to be displayed. - * If not set the core will create its own window. + * For MacOS, Linux, Windows: if not set or zero the core will create its own window, unless the special id -1 is given. **/ void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id){ -#ifdef VIDEO_ENABLED - LinphoneCall *call=linphone_core_get_current_call(lc); + if (id==0 || id==(unsigned long)-1){ + unset_video_window_id(lc,FALSE,id); + } lc->video_window_id=id; - if (call!=NULL && call->videostream){ - video_stream_set_native_window_id(call->videostream,id); +#ifdef VIDEO_ENABLED + { + LinphoneCall *call=linphone_core_get_current_call(lc); + if (call!=NULL && call->videostream){ + video_stream_set_native_window_id(call->videostream,id); + } } #endif } @@ -4669,30 +4960,41 @@ void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id * @ingroup media_parameters **/ unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc){ + if (lc->preview_window_id){ + /*case where the id was set by the app previously*/ + return lc->preview_window_id; + }else{ + /*case where we want the id automatically created by mediastreamer2 (desktop versions only)*/ #ifdef VIDEO_ENABLED - LinphoneCall *call=linphone_core_get_current_call (lc); - if (call && call->videostream) - return video_stream_get_native_preview_window_id(call->videostream); - if (lc->previewstream) - return video_preview_get_native_window_id(lc->previewstream); + LinphoneCall *call=linphone_core_get_current_call(lc); + if (call && call->videostream) + return video_stream_get_native_preview_window_id(call->videostream); + if (lc->previewstream) + return video_preview_get_native_window_id(lc->previewstream); #endif - return lc->preview_window_id; + } + return 0; } /** * @ingroup media_parameters * Set the native window id where the preview video (local camera) is to be displayed. * This has to be used in conjonction with linphone_core_use_preview_window(). - * If not set the core will create its own window. + * MacOS, Linux, Windows: if not set or zero the core will create its own window, unless the special id -1 is given. **/ void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id){ -#ifdef VIDEO_ENABLED - LinphoneCall *call=linphone_core_get_current_call(lc); + if (id==0 || id==(unsigned long)-1){ + unset_video_window_id(lc,TRUE,id); + } lc->preview_window_id=id; - if (call!=NULL && call->videostream){ - video_stream_set_native_preview_window_id(call->videostream,id); - }else if (lc->previewstream){ - video_preview_set_native_window_id(lc->previewstream,id); +#ifdef VIDEO_ENABLED + { + LinphoneCall *call=linphone_core_get_current_call(lc); + if (call!=NULL && call->videostream){ + video_stream_set_native_preview_window_id(call->videostream,id); + }else if (lc->previewstream){ + video_preview_set_native_window_id(lc->previewstream,id); + } } #endif } @@ -4710,11 +5012,6 @@ void linphone_core_show_video(LinphoneCore *lc, bool_t show){ #endif } -/** - * Tells the core to use a separate window for local camera preview video, instead of - * inserting local view within the remote video window. - * -**/ void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno){ lc->use_preview_window=yesno; } @@ -4736,7 +5033,7 @@ int linphone_core_get_device_rotation(LinphoneCore *lc ) { * **/ void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation) { - ms_message("%s : rotation=%d\n", __FUNCTION__, rotation); + if (rotation!=lc->device_rotation) ms_message("%s : rotation=%d\n", __FUNCTION__, rotation); lc->device_rotation = rotation; #ifdef VIDEO_ENABLED { @@ -4759,14 +5056,17 @@ int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc) { } static MSVideoSizeDef supported_resolutions[]={ -#ifdef ENABLE_HD - { {MS_VIDEO_SIZE_1080P_W,MS_VIDEO_SIZE_1080P_H} , "1080p" }, - { {MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H} , "1080p" }, -#endif + { { MS_VIDEO_SIZE_1080P_W,MS_VIDEO_SIZE_1080P_H } , "1080p" }, + { { MS_VIDEO_SIZE_UXGA_W, MS_VIDEO_SIZE_UXGA_H } , "uxga" }, + { { MS_VIDEO_SIZE_SXGA_MINUS_W, MS_VIDEO_SIZE_SXGA_MINUS_H } , "sxga-" }, + { { MS_VIDEO_SIZE_720P_W,MS_VIDEO_SIZE_720P_H } , "720p" }, + { { MS_VIDEO_SIZE_XGA_W, MS_VIDEO_SIZE_XGA_H } , "xga" }, { {MS_VIDEO_SIZE_SVGA_W,MS_VIDEO_SIZE_SVGA_H} , "svga" }, { {MS_VIDEO_SIZE_4CIF_W,MS_VIDEO_SIZE_4CIF_H} , "4cif" }, { {MS_VIDEO_SIZE_VGA_W,MS_VIDEO_SIZE_VGA_H} , "vga" }, +#ifdef __ios { {MS_VIDEO_SIZE_IOS_MEDIUM_H,MS_VIDEO_SIZE_IOS_MEDIUM_W} , "ios-medium" }, +#endif { {MS_VIDEO_SIZE_CIF_W,MS_VIDEO_SIZE_CIF_H} , "cif" }, { {MS_VIDEO_SIZE_QVGA_W,MS_VIDEO_SIZE_QVGA_H} , "qvga" }, { {MS_VIDEO_SIZE_QCIF_W,MS_VIDEO_SIZE_QCIF_H} , "qcif" }, @@ -4943,7 +5243,7 @@ void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){ return; } - if (duration_ms>0) + if (duration_ms > 0) ms_filter_call_method(f, MS_DTMF_GEN_PLAY, &dtmf); else ms_filter_call_method(f, MS_DTMF_GEN_START, &dtmf); } @@ -5043,7 +5343,7 @@ void linphone_core_set_mtu(LinphoneCore *lc, int mtu){ }else ms_set_mtu(0);//use mediastreamer2 default value } -void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneWaitingCallback cb, void *user_context){ +void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneCoreWaitingCallback cb, void *user_context){ lc->wait_cb=cb; lc->wait_ctx=user_context; } @@ -5058,11 +5358,7 @@ void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float if (lc->wait_cb){ lc->wait_ctx=lc->wait_cb(lc,lc->wait_ctx,LinphoneWaitingProgress,purpose,progress); }else{ -#ifdef WIN32 - Sleep(50000); -#else - usleep(50000); -#endif + ms_usleep(50000); } } @@ -5103,7 +5399,11 @@ void net_config_uninit(LinphoneCore *lc) net_config_t *config=&lc->net_conf; if (config->stun_server!=NULL){ - ms_free(lc->net_conf.stun_server); + ms_free(config->stun_server); + } + if (config->stun_addrinfo){ + freeaddrinfo(config->stun_addrinfo); + config->stun_addrinfo=NULL; } if (config->nat_address!=NULL){ lp_config_set_string(lc->config,"net","nat_address",config->nat_address); @@ -5121,6 +5421,7 @@ void sip_config_uninit(LinphoneCore *lc) MSList *elem; int i; sip_config_t *config=&lc->sip_conf; + bool_t still_registered=TRUE; lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname); lp_config_set_string(lc->config,"sip","contact",config->contact); @@ -5131,32 +5432,46 @@ void sip_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up); lp_config_set_int(lc->config,"sip","register_only_when_upnp_is_ok",config->register_only_when_upnp_is_ok); - - for(elem=config->proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ + for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); linphone_proxy_config_edit(cfg); /* to unregister */ } + + ms_message("Unregistration started."); - for (i=0;i<20;i++){ + for (i=0;i<20&&still_registered;i++){ + still_registered=FALSE; sal_iterate(lc->sal); -#ifndef WIN32 - usleep(100000); -#else - Sleep(100); -#endif + for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ + LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); + still_registered|=linphone_proxy_config_is_registered(cfg); + } + ms_usleep(100000); } - + if (i>=20) ms_warning("Cannot complete unregistration, giving up"); ms_list_for_each(config->proxies,(void (*)(void*)) linphone_proxy_config_destroy); ms_list_free(config->proxies); config->proxies=NULL; - linphone_proxy_config_write_to_config_file(lc->config,NULL,i); /*mark the end */ + /*no longuer need to write proxy config if not changedlinphone_proxy_config_write_to_config_file(lc->config,NULL,i);*/ /*mark the end */ ms_list_for_each(lc->auth_info,(void (*)(void*))linphone_auth_info_destroy); ms_list_free(lc->auth_info); lc->auth_info=NULL; + /*now that we are unregisted, we no longer need the tunnel.*/ +#ifdef TUNNEL_ENABLED + if (lc->tunnel) { + linphone_tunnel_destroy(lc->tunnel); + lc->tunnel=NULL; + ms_message("Tunnel destroyed."); + } +#endif + + sal_reset_transports(lc->sal); + sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/ + sal_iterate(lc->sal); /*make sure event are purged*/ sal_uninit(lc->sal); lc->sal=NULL; @@ -5198,7 +5513,7 @@ static void sound_config_uninit(LinphoneCore *lc) if (config->local_ring) ms_free(config->local_ring); if (config->remote_ring) ms_free(config->remote_ring); - ms_snd_card_manager_destroy(); + } static void video_config_uninit(LinphoneCore *lc) @@ -5254,11 +5569,17 @@ static void codecs_config_uninit(LinphoneCore *lc) void ui_config_uninit(LinphoneCore* lc) { + ms_message("Destroying friends."); if (lc->friends){ ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_destroy); ms_list_free(lc->friends); lc->friends=NULL; } + if (lc->presence_model) { + linphone_presence_model_unref(lc->presence_model); + lc->presence_model = NULL; + } + ms_message("Destroying friends done."); } /** @@ -5269,10 +5590,14 @@ void ui_config_uninit(LinphoneCore* lc) * sections and pairs of key=value in the configuration file. * **/ -LpConfig *linphone_core_get_config(LinphoneCore *lc){ +LpConfig * linphone_core_get_config(LinphoneCore *lc){ return lc->config; } +LpConfig * linphone_core_create_lp_config(LinphoneCore *lc, const char *filename) { + return lp_config_new(filename); +} + static void linphone_core_uninit(LinphoneCore *lc) { linphone_core_free_hooks(lc); @@ -5283,20 +5608,10 @@ static void linphone_core_uninit(LinphoneCore *lc) LinphoneCall *the_call = lc->calls->data; linphone_core_terminate_call(lc,the_call); linphone_core_iterate(lc); -#ifdef WIN32 - Sleep(50000); -#else - usleep(50000); -#endif + ms_usleep(50000); } -#ifdef BUILD_UPNP - if(lc->upnp != NULL) { - linphone_upnp_context_destroy(lc->upnp); - lc->upnp = NULL; - } -#endif //BUILD_UPNP - if (lc->friends) + if (lc->friends) /* FIXME we should wait until subscription to complete*/ ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down"); #ifdef VIDEO_ENABLED @@ -5305,21 +5620,31 @@ static void linphone_core_uninit(LinphoneCore *lc) lc->previewstream=NULL; } #endif + ms_event_queue_destroy(lc->msevq); lc->msevq=NULL; /* save all config */ + ui_config_uninit(lc); + sip_config_uninit(lc); net_config_uninit(lc); rtp_config_uninit(lc); - if (lc->ringstream) ring_stop(lc->ringstream); + linphone_core_stop_ringing(lc); sound_config_uninit(lc); video_config_uninit(lc); codecs_config_uninit(lc); - ui_config_uninit(lc); - sip_config_uninit(lc); + + sip_setup_unregister_all(); + +#ifdef BUILD_UPNP + if(lc->upnp != NULL) { + linphone_upnp_context_destroy(lc->upnp); + lc->upnp = NULL; + } +#endif //BUILD_UPNP + if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config); lp_config_destroy(lc->config); lc->config = NULL; /* Mark the config as NULL to block further calls */ - sip_setup_unregister_all(); ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); lc->call_logs=ms_list_free(lc->call_logs); @@ -5337,25 +5662,28 @@ static void linphone_core_uninit(LinphoneCore *lc) if(lc->rec_file!=NULL){ ms_free(lc->rec_file); } - + if(lc->presence_model){ + linphone_presence_model_unref(lc->presence_model); + } linphone_core_free_payload_types(lc); linphone_core_message_storage_close(lc); - ortp_exit(); + ms_exit(); linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); -#ifdef TUNNEL_ENABLED - if (lc->tunnel) linphone_tunnel_destroy(lc->tunnel); -#endif } static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){ - ms_message("Network state is now [%s]",isReachable?"UP":"DOWN"); // second get the list of available proxies const MSList *elem=linphone_core_get_proxy_config_list(lc); + + if (lc->network_reachable==isReachable) return; // no change, ignore. + + ms_message("Network state is now [%s]",isReachable?"UP":"DOWN"); for(;elem!=NULL;elem=elem->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; if (linphone_proxy_config_register_enabled(cfg) ) { if (!isReachable) { + linphone_proxy_config_stop_refreshing(cfg); linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone,"Registration impossible (network down)"); }else{ cfg->commit=TRUE; @@ -5365,21 +5693,24 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu lc->netup_time=curtime; lc->network_reachable=isReachable; - if(!isReachable) { + if (!lc->network_reachable){ + linphone_core_invalidate_friend_subscriptions(lc); sal_reset_transports(lc->sal); + }else{ + linphone_core_resolve_stun_server(lc); } #ifdef BUILD_UPNP if(lc->upnp == NULL) { - if(isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { - lc->upnp = linphone_upnp_context_new(lc); + if(isReachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) { + lc->upnp = linphone_upnp_context_new(lc); } } else { - if(!isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { + if(!isReachable && linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) { linphone_upnp_context_destroy(lc->upnp); lc->upnp = NULL; } } -#endif +#endif } void linphone_core_refresh_registers(LinphoneCore* lc) { @@ -5485,7 +5816,7 @@ int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call) } /** - * Specifiies a ring back tone to be played to far end during incoming calls. + * Specifies a ring back tone to be played to far end during incoming calls. **/ void linphone_core_set_remote_ringback_tone(LinphoneCore *lc, const char *file){ if (lc->sound_conf.ringback_tone){ @@ -5575,6 +5906,16 @@ const char *linphone_reason_to_string(LinphoneReason err){ return "Not answered"; case LinphoneReasonBusy: return "Busy"; + case LinphoneReasonMedia: + return "Incompatible media capabilities"; + case LinphoneReasonIOError: + return "IO error"; + case LinphoneReasonDoNotDisturb: + return "Do not distrub"; + case LinphoneReasonUnauthorized: + return "Unauthorized"; + case LinphoneReasonNotAcceptable: + return "Not acceptable here"; } return "unknown error"; } @@ -5610,10 +5951,26 @@ void linphone_core_start_dtmf_stream(LinphoneCore* lc) { lc->ringstream_autorelease=FALSE; /*disable autorelease mode*/ } -void linphone_core_stop_dtmf_stream(LinphoneCore* lc) { - if (lc->ringstream && lc->dmfs_playing_start_time!=0) { +/** + * Whenever the liblinphone is playing a ring to advertise an incoming call or ringback of an outgoing call, this function stops + * the ringing. Typical use is to stop ringing when the user requests to ignore the call. + * + * @param lc The LinphoneCore object + * + * @ingroup media_parameters +**/ +void linphone_core_stop_ringing(LinphoneCore* lc) { + if (lc->ringstream) { ring_stop(lc->ringstream); lc->ringstream=NULL; + lc->dmfs_playing_start_time=0; + lc->ringstream_autorelease=TRUE; + } +} + +void linphone_core_stop_dtmf_stream(LinphoneCore* lc) { + if (lc->dmfs_playing_start_time!=0) { + linphone_core_stop_ringing(lc); } } @@ -5679,13 +6036,18 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc){ } LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri) { + MSList *calls; + LinphoneCall *c; + const LinphoneAddress *address; + char *current_uri; + if (uri == NULL) return NULL; - MSList *calls=lc->calls; + calls=lc->calls; while(calls) { - LinphoneCall *c=(LinphoneCall*)calls->data; + c=(LinphoneCall*)calls->data; calls=calls->next; - const LinphoneAddress *address = linphone_call_get_remote_address(c); - char *current_uri=linphone_address_as_string_uri_only(address); + address = linphone_call_get_remote_address(c); + current_uri=linphone_address_as_string_uri_only(address); if (strcmp(uri,current_uri)==0) { ms_free(current_uri); return c; @@ -5704,10 +6066,9 @@ LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const cha * @param lc The LinphoneCore **/ bool_t linphone_core_sound_resources_locked(LinphoneCore *lc){ - MSList *calls=lc->calls; - while(calls) { - LinphoneCall *c=(LinphoneCall*)calls->data; - calls=calls->next; + MSList *elem; + for(elem=lc->calls;elem!=NULL;elem=elem->next) { + LinphoneCall *c=(LinphoneCall*)elem->data; switch (c->state) { case LinphoneCallOutgoingInit: case LinphoneCallOutgoingProgress: @@ -5717,6 +6078,7 @@ bool_t linphone_core_sound_resources_locked(LinphoneCore *lc){ case LinphoneCallRefered: case LinphoneCallIncomingEarlyMedia: case LinphoneCallUpdating: + ms_message("Call %p is locking sound resources.",c); return TRUE; default: break; @@ -5744,7 +6106,7 @@ bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, Linphone return FALSE; } -int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc) { +int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption menc) { const char *type="none"; int ret=0; if (menc == LinphoneMediaEncryptionSRTP){ @@ -5789,6 +6151,7 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para params->has_video=linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate; params->media_encryption=linphone_core_get_media_encryption(lc); params->in_conference=FALSE; + params->privacy=LinphonePrivacyDefault; } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 93ab0ca88..b9c9a5030 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -30,9 +30,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphone/sipsetup.h" #endif +#include "lpconfig.h" + #define LINPHONE_IPADDR_SIZE 64 #define LINPHONE_HOSTNAME_SIZE 128 +#ifndef LINPHONE_PUBLIC + #define LINPHONE_PUBLIC MS2_PUBLIC +#endif + #ifdef __cplusplus extern "C" { #endif @@ -44,8 +50,19 @@ struct _LinphoneCore; */ typedef struct _LinphoneCore LinphoneCore; -struct _LpConfig; +/** + * Disable a sip transport + * Use with #LCSipTransports + * @ingroup initializing + */ +#define LC_SIP_TRANSPORT_DISABLED 0 +/** + * Randomly chose a sip port for this transport + * Use with #LCSipTransports + * @ingroup initializing + */ +#define LC_SIP_TRANSPORT_RANDOM -1 /** * Linphone core SIP transport ports. @@ -72,6 +89,19 @@ typedef struct _LCSipTransports{ } LCSipTransports; +/** + * Enum describing transport type for LinphoneAddress. +**/ +enum _LinphoneTransportType{ + LinphoneTransportUdp, + LinphoneTransportTcp, + LinphoneTransportTls, + LinphoneTransportDtls +}; +/*this enum MUST be kept in sync with the SalTransport from sal.h*/ + +typedef enum _LinphoneTransportType LinphoneTransportType; + /** * Object that represents a SIP address. * @@ -87,38 +117,109 @@ typedef struct _LCSipTransports{ * @var LinphoneAddress */ typedef struct SalAddress LinphoneAddress; + +/** + * The LinphoneContent struct holds data that can be embedded in a signaling message. + * @ingroup misc +**/ +struct _LinphoneContent{ + char *type; /** + */ + LinphonePrivacyUser=0x1, + /** + * Request that privacy services modify headers that cannot + * be set arbitrarily by the user (Contact/Via). + */ + LinphonePrivacyHeader=0x2, + /** + * Request that privacy services provide privacy for session + * media + */ + LinphonePrivacySession=0x4, + /** + * rfc3325 + * The presence of this privacy type in + * a Privacy header field indicates that the user would like the Network + * Asserted Identity to be kept private with respect to SIP entities + * outside the Trust Domain with which the user authenticated. Note + * that a user requesting multiple types of privacy MUST include all of + * the requested privacy types in its Privacy header field value + * + */ + LinphonePrivacyId=0x8, + /** + * Privacy service must perform the specified services or + * fail the request + * + **/ + LinphonePrivacyCritical=0x10, + + /** + * Special keyword to use privacy as defined either globally or by proxy using linphone_proxy_config_set_privacy() + */ + LinphonePrivacyDefault=0x8000, +} LinphonePrivacy; +/* + * a mask of #LinphonePrivacy values + * */ +typedef unsigned int LinphonePrivacyMask; + + +LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy); +LINPHONE_PUBLIC void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy); +LINPHONE_PUBLIC LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params); + + +struct _LinphoneInfoMessage; +/** + * The LinphoneInfoMessage is an object representing an informational message sent or received by the core. +**/ +typedef struct _LinphoneInfoMessage LinphoneInfoMessage; + +LINPHONE_PUBLIC LinphoneInfoMessage *linphone_core_create_info_message(LinphoneCore*lc); +LINPHONE_PUBLIC int linphone_call_send_info_message(struct _LinphoneCall *call, const LinphoneInfoMessage *info); +LINPHONE_PUBLIC void linphone_info_message_add_header(LinphoneInfoMessage *im, const char *name, const char *value); +LINPHONE_PUBLIC const char *linphone_info_message_get_header(const LinphoneInfoMessage *im, const char *name); +LINPHONE_PUBLIC void linphone_info_message_set_content(LinphoneInfoMessage *im, const LinphoneContent *content); +LINPHONE_PUBLIC const LinphoneContent * linphone_info_message_get_content(const LinphoneInfoMessage *im); +LINPHONE_PUBLIC const char *linphone_info_message_get_from(const LinphoneInfoMessage *im); +LINPHONE_PUBLIC void linphone_info_message_destroy(LinphoneInfoMessage *im); +LINPHONE_PUBLIC LinphoneInfoMessage *linphone_info_message_copy(const LinphoneInfoMessage *orig); + -const char *linphone_reason_to_string(LinphoneReason err); /** * Structure describing policy regarding video streams establishments. @@ -255,16 +453,7 @@ struct _LinphoneVideoPolicy{ **/ typedef struct _LinphoneVideoPolicy LinphoneVideoPolicy; -/** - * The LinphoneCall object represents a call issued or received by the LinphoneCore - * @ingroup call_control -**/ -struct _LinphoneCall; -/** - * The LinphoneCall object represents a call issued or received by the LinphoneCore - * @ingroup call_control -**/ -typedef struct _LinphoneCall LinphoneCall; + /** @@ -306,6 +495,7 @@ enum _LinphoneUpnpState{ LinphoneUpnpStateNotAvailable, /**< uPnP is not available */ LinphoneUpnpStateOk, /**< uPnP is enabled */ LinphoneUpnpStateKo, /**< uPnP processing has failed */ + LinphoneUpnpStateBlacklisted, /**< IGD router is blacklisted */ }; /** @@ -351,12 +541,12 @@ struct _LinphoneCallStats { * @} **/ -const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); -const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); +LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_audio_stats(LinphoneCall *call); +LINPHONE_PUBLIC const LinphoneCallStats *linphone_call_get_video_stats(LinphoneCall *call); /** Callback prototype */ -typedef void (*LinphoneCallCbFunc)(struct _LinphoneCall *call,void * user_data); +typedef void (*LinphoneCallCbFunc)(LinphoneCall *call,void * user_data); /** * LinphoneCallState enum represents the different state a call can reach into. @@ -385,53 +575,56 @@ typedef enum _LinphoneCallState{ LinphoneCallReleased /**< The call object is no more retained by the core */ } LinphoneCallState; -const char *linphone_call_state_to_string(LinphoneCallState cs); +LINPHONE_PUBLIC const char *linphone_call_state_to_string(LinphoneCallState cs); -LinphoneCore *linphone_call_get_core(const LinphoneCall *call); -LinphoneCallState linphone_call_get_state(const LinphoneCall *call); +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); -const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc); -const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call); -char *linphone_call_get_remote_address_as_string(const LinphoneCall *call); -LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call); -LinphoneCall * linphone_call_ref(LinphoneCall *call); -void linphone_call_unref(LinphoneCall *call); -LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); -const char *linphone_call_get_refer_to(const LinphoneCall *call); -bool_t linphone_call_has_transfer_pending(const LinphoneCall *call); -LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call); -int linphone_call_get_duration(const LinphoneCall *call); -const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); -const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); -void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); -bool_t linphone_call_camera_enabled(const LinphoneCall *lc); -int linphone_call_take_video_snapshot(LinphoneCall *call, const char *file); -LinphoneReason linphone_call_get_reason(const LinphoneCall *call); -const char *linphone_call_get_remote_user_agent(LinphoneCall *call); -const char *linphone_call_get_remote_contact(LinphoneCall *call); -float linphone_call_get_play_volume(LinphoneCall *call); -float linphone_call_get_record_volume(LinphoneCall *call); -float linphone_call_get_current_quality(LinphoneCall *call); -float linphone_call_get_average_quality(LinphoneCall *call); -const char* linphone_call_get_authentication_token(LinphoneCall *call); -bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call); -void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified); -void linphone_call_send_vfu_request(LinphoneCall *call); -void *linphone_call_get_user_pointer(LinphoneCall *call); -void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); -void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data); -LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call); -void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy); -void linphone_call_start_recording(LinphoneCall *call); -void linphone_call_stop_recording(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); +LINPHONE_PUBLIC LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCall * linphone_call_ref(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_unref(LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call); +LINPHONE_PUBLIC const char *linphone_call_get_refer_to(const LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_has_transfer_pending(const LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCall *linphone_call_get_transferer_call(const LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCall *linphone_call_get_transfer_target_call(const LinphoneCall *call); +LINPHONE_PUBLIC LinphoneCall *linphone_call_get_replaced_call(LinphoneCall *call); +LINPHONE_PUBLIC int linphone_call_get_duration(const LinphoneCall *call); +LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call); +LINPHONE_PUBLIC const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_enable_camera(LinphoneCall *lc, bool_t enabled); +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 char *linphone_call_get_remote_user_agent(LinphoneCall *call); +LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(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); +LINPHONE_PUBLIC float linphone_call_get_average_quality(LinphoneCall *call); +LINPHONE_PUBLIC const char* linphone_call_get_authentication_token(LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t verified); +LINPHONE_PUBLIC void linphone_call_send_vfu_request(LinphoneCall *call); +LINPHONE_PUBLIC void *linphone_call_get_user_pointer(LinphoneCall *call); +LINPHONE_PUBLIC void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); +LINPHONE_PUBLIC void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data); +LINPHONE_PUBLIC LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call); +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 - *@return TRUE if part of a conference. + * @param call #LinphoneCall + * @return TRUE if part of a conference. * - @ingroup call_control + * @deprecated + * @ingroup call_control */ -bool_t linphone_call_is_in_conference(const LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_is_in_conference(const LinphoneCall *call); /** * Enables or disable echo cancellation for this call * @param call @@ -439,13 +632,13 @@ bool_t linphone_call_is_in_conference(const LinphoneCall *call); * * @ingroup media_parameters **/ -void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t val) ; +LINPHONE_PUBLIC void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t val) ; /** * Returns TRUE if echo cancellation is enabled. * * @ingroup media_parameters **/ -bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *lc); +LINPHONE_PUBLIC bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *lc); /** * Enables or disable echo limiter for this call * @param call @@ -453,13 +646,13 @@ bool_t linphone_call_echo_cancellation_enabled(LinphoneCall *lc); * * @ingroup media_parameters **/ -void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val); +LINPHONE_PUBLIC void linphone_call_enable_echo_limiter(LinphoneCall *call, bool_t val); /** * Returns TRUE if echo limiter is enabled. * * @ingroup media_parameters **/ -bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call); /*keep this in sync with mediastreamer2/msvolume.h*/ @@ -506,23 +699,23 @@ typedef enum _LinphoneRegistrationState{ * Human readable version of the #LinphoneRegistrationState * @param cs sate */ -const char *linphone_registration_state_to_string(LinphoneRegistrationState cs); - -LinphoneProxyConfig *linphone_proxy_config_new(void); -int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr); -int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity); -int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route); -void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int expires); +LINPHONE_PUBLIC const char *linphone_registration_state_to_string(LinphoneRegistrationState cs); +LINPHONE_PUBLIC LinphoneProxyConfig *linphone_proxy_config_new(void); +LINPHONE_PUBLIC int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr); +LINPHONE_PUBLIC int linphone_proxy_config_set_identity(LinphoneProxyConfig *obj, const char *identity); +LINPHONE_PUBLIC int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route); +LINPHONE_PUBLIC void linphone_proxy_config_set_expires(LinphoneProxyConfig *obj, int expires); +#define linphone_proxy_config_expires linphone_proxy_config_set_expires /** * Indicates either or not, REGISTRATION must be issued for this #LinphoneProxyConfig . *
In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule. * @param obj object pointer * @param val if true, registration will be engaged */ -void linphone_proxy_config_enable_register(LinphoneProxyConfig *obj, bool_t val); +LINPHONE_PUBLIC void linphone_proxy_config_enable_register(LinphoneProxyConfig *obj, bool_t val); #define linphone_proxy_config_enableregister linphone_proxy_config_enable_register -void linphone_proxy_config_edit(LinphoneProxyConfig *obj); -int linphone_proxy_config_done(LinphoneProxyConfig *obj); +LINPHONE_PUBLIC void linphone_proxy_config_edit(LinphoneProxyConfig *obj); +LINPHONE_PUBLIC int linphone_proxy_config_done(LinphoneProxyConfig *obj); /** * Indicates either or not, PUBLISH must be issued for this #LinphoneProxyConfig . *
In case this #LinphoneProxyConfig has been added to #LinphoneCore, follows the linphone_proxy_config_edit() rule. @@ -530,30 +723,61 @@ int linphone_proxy_config_done(LinphoneProxyConfig *obj); * @param val if true, publish will be engaged * */ -void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val); -void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val); -void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix); +LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val); +LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val); +LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix); -LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *obj); -bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj); -const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg); +/** + * Get the registration state of the given proxy config. + * @param[in] obj #LinphoneProxyConfig object. + * @returns The registration state of the proxy config. +**/ +LINPHONE_PUBLIC LinphoneRegistrationState linphone_proxy_config_get_state(const LinphoneProxyConfig *obj); -const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj); -const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj); -bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj); -const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj); -int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj); -bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj); -void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj); -const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj); -void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params); -struct _LinphoneCore * linphone_proxy_config_get_core(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj); -bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg); -const char * linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg); +/** + * Get the domain name of the given proxy config. + * @param[in] cfg #LinphoneProxyConfig object. + * @returns The domain name of the proxy config. +**/ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_domain(const LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj); +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); + +/** + * 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 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); + +/** + * Get the reason why registration failed when the proxy config state is LinphoneRegistrationFailed. + * @param[in] cfg #LinphoneProxyConfig object. + * @returns The reason why registration failed for this proxy config. +**/ LinphoneReason linphone_proxy_config_get_error(const LinphoneProxyConfig *cfg); +/* + * return the transport from either : service route, route, or addr + * @returns cfg object + * @return transport as string (I.E udp, tcp, tls, dtls)*/ + +LINPHONE_PUBLIC const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg); + + /* 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); @@ -562,22 +786,35 @@ SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg); /** * normalize a human readable phone number into a basic string. 888-444-222 becomes 888444222 */ -int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len); +LINPHONE_PUBLIC int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const char *username, char *result, size_t result_len); /* * attached a user data to a proxy config */ -void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr, void * ud); +LINPHONE_PUBLIC void linphone_proxy_config_set_user_data(LinphoneProxyConfig *cr, void * ud); /* * get user data to a proxy config. return null if any */ -void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr); +LINPHONE_PUBLIC void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr); + +/** + * Set default privacy policy for all calls routed through this proxy. + * @param params to be modified + * @param LinphonePrivacy to configure privacy + * */ +LINPHONE_PUBLIC void linphone_proxy_config_set_privacy(LinphoneProxyConfig *params, LinphonePrivacyMask privacy); +/** + * Get default privacy policy for all calls routed through this proxy. + * @param params object + * @return Privacy mode + * */ +LINPHONE_PUBLIC LinphonePrivacyMask linphone_proxy_config_get_privacy(const LinphoneProxyConfig *params); /** * @} **/ typedef struct _LinphoneAccountCreator{ - struct _LinphoneCore *lc; + LinphoneCore *lc; struct _SipSetupContext *ssctx; char *username; char *password; @@ -588,7 +825,7 @@ typedef struct _LinphoneAccountCreator{ bool_t succeeded; }LinphoneAccountCreator; -LinphoneAccountCreator *linphone_account_creator_new(struct _LinphoneCore *core, const char *type); +LinphoneAccountCreator *linphone_account_creator_new(LinphoneCore *core, const char *type); void linphone_account_creator_set_username(LinphoneAccountCreator *obj, const char *username); void linphone_account_creator_set_password(LinphoneAccountCreator *obj, const char *password); void linphone_account_creator_set_domain(LinphoneAccountCreator *obj, const char *domain); @@ -630,23 +867,25 @@ struct _LinphoneAuthInfo; **/ typedef struct _LinphoneAuthInfo LinphoneAuthInfo; -LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, - const char *passwd, const char *ha1,const char *realm); -void linphone_auth_info_set_passwd(LinphoneAuthInfo *info, const char *passwd); -void linphone_auth_info_set_username(LinphoneAuthInfo *info, const char *username); -void linphone_auth_info_set_userid(LinphoneAuthInfo *info, const char *userid); -void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm); -void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1); +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); +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); +LINPHONE_PUBLIC void linphone_auth_info_set_realm(LinphoneAuthInfo *info, const char *realm); +LINPHONE_PUBLIC void linphone_auth_info_set_domain(LinphoneAuthInfo *info, const char *domain); +LINPHONE_PUBLIC void linphone_auth_info_set_ha1(LinphoneAuthInfo *info, const char *ha1); -const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i); -const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i); -const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i); -const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *i); -const char *linphone_auth_info_get_ha1(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_username(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_passwd(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_userid(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_realm(const LinphoneAuthInfo *i); +LINPHONE_PUBLIC const char *linphone_auth_info_get_domain(const LinphoneAuthInfo *i); +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(struct _LpConfig *config, int pos); +LinphoneAuthInfo * linphone_auth_info_new_from_config_file(LpConfig *config, int pos); struct _LinphoneChatRoom; @@ -668,14 +907,14 @@ typedef struct _LinphoneChatMessage LinphoneChatMessage; typedef struct _LinphoneChatRoom LinphoneChatRoom; /** - *LinphoneChatMessageState is used to notify if messages have been succesfully delivered or not. + * LinphoneChatMessageState is used to notify if messages have been succesfully delivered or not. */ -typedef enum _LinphoneChatMessageStates { - LinphoneChatMessageStateIdle, /** Status on this subscription request is notified by \link linphone_friend_set_inc_subscribe_policy() changing policy \endlink for this friend - * @param lc #LinphoneCore object - * @param lf #LinphoneFriend corresponding to the subscriber - * @param url of the subscriber + * Status on this subscription request is notified by \link linphone_friend_set_inc_subscribe_policy() changing policy \endlink for this friend + * @param lc #LinphoneCore object + * @param lf #LinphoneFriend corresponding to the subscriber + * @param url of the subscriber * Callback prototype - * */ -typedef void (*NewSubscribtionRequestCb)(struct _LinphoneCore *lc, LinphoneFriend *lf, const char *url); -/** Callback prototype */ -typedef void (*AuthInfoRequested)(struct _LinphoneCore *lc, const char *realm, const char *username); -/** Callback prototype */ -typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl); + */ +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. + * @param username the username that needs to be authenticated. + * Application shall reply to this callback using linphone_core_add_auth_info(). + */ +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 + * @param newcl the new call log entry added. + */ +typedef void (*LinphoneCoreCallLogUpdatedCb)(LinphoneCore *lc, LinphoneCallLog *newcl); + /** * Callback prototype - * @deprecated use #MessageReceived instead. + * @deprecated use #LinphoneMessageReceived instead. * * @param lc #LinphoneCore object * @param room #LinphoneChatRoom involved in this conversation. Can be be created by the framework in case \link #LinphoneAddress the from \endlink is not present in any chat room. * @param from #LinphoneAddress from * @param message incoming message - * */ -typedef void (*TextMessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message); + */ +typedef void (*LinphoneCoreTextMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message); + /** * Chat message callback prototype * * @param lc #LinphoneCore object * @param room #LinphoneChatRoom involved in this conversation. Can be be created by the framework in case \link #LinphoneAddress the from \endlink is not present in any chat room. * @param LinphoneChatMessage incoming message - * */ -typedef void (*MessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); + */ +typedef void (*LinphoneCoreMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message); +/** + * Callback for being notified of DTMFs received. + * @param lc the linphone core + * @param call the call that received the dtmf + * @param dtmf the ascii code of the dtmf + */ +typedef void (*LinphoneCoreDtmfReceivedCb)(LinphoneCore* lc, LinphoneCall *call, int dtmf); + /** Callback prototype */ -typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf); +typedef void (*LinphoneCoreReferReceivedCb)(LinphoneCore *lc, const char *refer_to); /** Callback prototype */ -typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to); -/** Callback prototype */ -typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf); -/** Callback prototype for in progress transfers. The new_call_state is the state of the call resulting of the transfer, at the other party. */ -typedef void (*LinphoneTransferStateChanged)(struct _LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state); -/** Callback prototype for receiving quality statistics for calls*/ -typedef void (*CallStatsUpdated)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats); +typedef void (*LinphoneCoreBuddyInfoUpdatedCb)(LinphoneCore *lc, LinphoneFriend *lf); +/** + * Callback for notifying progresses of transfers. + * @param lc the LinphoneCore + * @param transfered the call that was transfered + * @param new_call_state the state of the call to transfer target at the far end. + */ +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 + * @param stats the call statistics. + */ +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. + */ +typedef void (*LinphoneCoreInfoReceivedCb)(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); /** * This structure holds all callbacks that the application should implement. * None is mandatory. **/ -typedef struct _LinphoneVTable{ - LinphoneGlobalStateCb global_state_changed; /** A text message has been received */ - MessageReceived message_received; /** a message is received, can be text or external body*/ - DtmfReceived dtmf_received; /**< A dtmf has been received received */ - ReferReceived refer_received; /**< An out of call refer was received */ - CallEncryptionChangedCb call_encryption_changed; /** A text message has been received */ } LinphoneCoreVTable; /** @@ -855,13 +1170,16 @@ typedef struct _LCCallbackObj }LCCallbackObj; - -typedef enum _LinphoneFirewallPolicy{ - LinphonePolicyNoFirewall, - LinphonePolicyUseNatAddress, - LinphonePolicyUseStun, - LinphonePolicyUseIce, - LinphonePolicyUseUpnp, +/** + * Policy to use to pass through firewalls. + * @ingroup network_parameters +**/ +typedef enum _LinphoneFirewallPolicy { + LinphonePolicyNoFirewall, /**< Do not use any mechanism to pass through firewalls */ + LinphonePolicyUseNatAddress, /**< Use the specified public adress */ + LinphonePolicyUseStun, /**< Use a STUN server to get the public address */ + LinphonePolicyUseIce, /**< Use the ICE protocol */ + LinphonePolicyUseUpnp, /**< Use the uPnP protocol */ } LinphoneFirewallPolicy; typedef enum _LinphoneWaitingState{ @@ -869,7 +1187,7 @@ typedef enum _LinphoneWaitingState{ LinphoneWaitingProgress, LinphoneWaitingFinished } LinphoneWaitingState; -typedef void * (*LinphoneWaitingCallback)(struct _LinphoneCore *lc, void *context, LinphoneWaitingState ws, const char *purpose, float progress); +typedef void * (*LinphoneCoreWaitingCallback)(LinphoneCore *lc, void *context, LinphoneWaitingState ws, const char *purpose, float progress); /* THE main API */ @@ -881,7 +1199,7 @@ typedef void * (*LinphoneWaitingCallback)(struct _LinphoneCore *lc, void *contex * * @param logfunc The function pointer of the log handler. */ -void linphone_core_set_log_handler(OrtpLogFunc logfunc); +LINPHONE_PUBLIC void linphone_core_set_log_handler(OrtpLogFunc logfunc); /** * Define a log file. * @@ -891,7 +1209,7 @@ void linphone_core_set_log_handler(OrtpLogFunc logfunc); * * @param file A pointer to the FILE structure of the file to write to. */ -void linphone_core_set_log_file(FILE *file); +LINPHONE_PUBLIC void linphone_core_set_log_file(FILE *file); /** * Define the log level. * @@ -902,15 +1220,15 @@ void linphone_core_set_log_file(FILE *file); * * @param loglevel A bitmask of the log levels to set. */ -void linphone_core_set_log_level(OrtpLogLevel loglevel); -void linphone_core_enable_logs(FILE *file); -void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc); -void linphone_core_disable_logs(void); -const char *linphone_core_get_version(void); -const char *linphone_core_get_user_agent_name(void); -const char *linphone_core_get_user_agent_version(void); +LINPHONE_PUBLIC void linphone_core_set_log_level(OrtpLogLevel loglevel); +LINPHONE_PUBLIC void linphone_core_enable_logs(FILE *file); +LINPHONE_PUBLIC void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc); +LINPHONE_PUBLIC void linphone_core_disable_logs(void); +LINPHONE_PUBLIC const char *linphone_core_get_version(void); +LINPHONE_PUBLIC const char *linphone_core_get_user_agent_name(void); +LINPHONE_PUBLIC const char *linphone_core_get_user_agent_version(void); -LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, +LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config, void* userdata); /** @@ -925,11 +1243,11 @@ LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, * callbacks) using linphone_core_get_user_data(). * @see linphone_core_new **/ -LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata); +LINPHONE_PUBLIC LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, LpConfig *config, void *userdata); /* function to be periodically called in a main loop */ /* For ICE to work properly it should be called every 20ms */ -void linphone_core_iterate(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_iterate(LinphoneCore *lc); #if 0 /*not implemented yet*/ /** * @ingroup initializing @@ -950,113 +1268,145 @@ const char* linphone_core_get_device_identifier(const LinphoneCore *lc); #endif /*sets the user-agent string in sip messages, ideally called just after linphone_core_new() or linphone_core_init() */ -void linphone_core_set_user_agent(LinphoneCore *lc, const char *ua_name, const char *version); +LINPHONE_PUBLIC void linphone_core_set_user_agent(LinphoneCore *lc, const char *ua_name, const char *version); -LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url); +LINPHONE_PUBLIC LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url); -LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url); +LINPHONE_PUBLIC LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url); -LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); +LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr); -LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *params); +LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_with_params(LinphoneCore *lc, const char *url, const LinphoneCallParams *params); -LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params); +LINPHONE_PUBLIC LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params); -int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); +LINPHONE_PUBLIC int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to); -int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest); +LINPHONE_PUBLIC int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest); -bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); +LINPHONE_PUBLIC bool_t linphone_core_inc_invite_pending(LinphoneCore*lc); -bool_t linphone_core_in_call(const LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_in_call(const LinphoneCore *lc); -LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc); -int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); +LINPHONE_PUBLIC int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); -int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri); +/** + * Redirect the specified call to the given redirect URI. + * @param[in] lc #LinphoneCore object. + * @param[in] call The #LinphoneCall to redirect. + * @param[in] redirect_uri The URI to redirect the call to. + * @returns 0 if successful, -1 on error. + * @ingroup call_control + */ +LINPHONE_PUBLIC int linphone_core_redirect_call(LinphoneCore *lc, LinphoneCall *call, const char *redirect_uri); -int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason); +LINPHONE_PUBLIC int linphone_core_decline_call(LinphoneCore *lc, LinphoneCall * call, LinphoneReason reason); -int linphone_core_terminate_all_calls(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_terminate_all_calls(LinphoneCore *lc); -int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_pause_all_calls(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_pause_all_calls(LinphoneCore *lc); -int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); +LINPHONE_PUBLIC int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); -int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); +LINPHONE_PUBLIC int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params); /** * @ingroup media_parameters * Get default call parameters reflecting current linphone core configuration * @param LinphoneCore object * @return LinphoneCallParams */ -LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc); -LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address); +LINPHONE_PUBLIC LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address); -void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf); +LINPHONE_PUBLIC void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf); -int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact); +LINPHONE_PUBLIC int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact); -const char *linphone_core_get_primary_contact(LinphoneCore *lc); +LINPHONE_PUBLIC const char *linphone_core_get_primary_contact(LinphoneCore *lc); -const char * linphone_core_get_identity(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); -bool_t linphone_core_ipv6_enabled(LinphoneCore *lc); -void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_ipv6_enabled(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val); -LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc); -const char * linphone_core_get_identity(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneAddress *linphone_core_get_primary_contact_parsed(LinphoneCore *lc); +LINPHONE_PUBLIC const char * linphone_core_get_identity(LinphoneCore *lc); /*0= no bandwidth limit*/ -void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw); -void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw); +LINPHONE_PUBLIC void linphone_core_set_download_bandwidth(LinphoneCore *lc, int bw); +LINPHONE_PUBLIC void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw); -int linphone_core_get_download_bandwidth(const LinphoneCore *lc); -int linphone_core_get_upload_bandwidth(const LinphoneCore *lc); +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); -void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime); -int linphone_core_get_download_ptime(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime); +LINPHONE_PUBLIC int linphone_core_get_download_ptime(LinphoneCore *lc); -void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime); +LINPHONE_PUBLIC void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime); -int linphone_core_get_upload_ptime(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_upload_ptime(LinphoneCore *lc); + +/** + * Enable or disable DNS SRV resolution. + * @param[in] lc #LinphoneCore object. + * @param[in] enable TRUE to enable DNS SRV resolution, FALSE to disable it. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC void linphone_core_enable_dns_srv(LinphoneCore *lc, bool_t enable); + +/** + * Tells whether DNS SRV resolution is enabled. + * @param[in] lc #LinphoneCore object. + * @returns TRUE if DNS SRV resolution is enabled, FALSE if disabled. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_dns_srv_enabled(const LinphoneCore *lc); /* returns a MSList of PayloadType */ -const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); +LINPHONE_PUBLIC const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); int linphone_core_set_audio_codecs(LinphoneCore *lc, MSList *codecs); /* returns a MSList of PayloadType */ -const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); +LINPHONE_PUBLIC const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc); int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); -bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt); /** - * Enable payload type - * @param linphone core - * @param pt payload type to enable, can be retrieve from #linphone_core_find_payload_type - * @param TRUE if enabled - * @return 0 if succed - * + * Tells whether the specified payload type is enabled. + * @param[in] lc #LinphoneCore object. + * @param[in] pt The #PayloadType we want to know is enabled or not. + * @returns TRUE if the payload type is enabled, FALSE if disabled. + * @ingroup media_parameters */ -int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable); +LINPHONE_PUBLIC bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt); + +/** + * Enable or disable the use of the specified payload type. + * @param[in] lc #LinphoneCore object. + * @param[in] pt The #PayloadType to enable or disable. It can be retrieved using #linphone_core_find_payload_type + * @param[in] enable TRUE to enable the payload type, FALSE to disable it. + * @return 0 if successful, any other value otherwise. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable); /** * Wildcard value used by #linphone_core_find_payload_type to ignore rate in search algorithm @@ -1078,99 +1428,138 @@ int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t * @param channels number of channels, can be #LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS * @return Returns NULL if not found. */ -PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ; +LINPHONE_PUBLIC PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate, int channels) ; -int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt); +LINPHONE_PUBLIC int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt); -const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt); +LINPHONE_PUBLIC const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt); -bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt); +LINPHONE_PUBLIC bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt); /** - * @ingroup proxy - *Create a proxy config with default value from Linphone core. - *@param lc #LinphoneCore object - *@return #LinphoneProxyConfig with defualt value set + * Create a proxy config with default values from Linphone core. + * @param[in] lc #LinphoneCore object + * @return #LinphoneProxyConfig with default values set + * @ingroup proxy */ -LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc); -int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); +LINPHONE_PUBLIC int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); -void linphone_core_clear_proxy_config(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_clear_proxy_config(LinphoneCore *lc); -void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); +LINPHONE_PUBLIC void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *config); -const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc); +LINPHONE_PUBLIC const MSList *linphone_core_get_proxy_config_list(const LinphoneCore *lc); -void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *config); +LINPHONE_PUBLIC void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *config); void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index); -int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config); +LINPHONE_PUBLIC int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config); -void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); +/** + * Create an authentication information with default values from Linphone core. + * @param[in] lc #LinphoneCore object + * @param[in] username String containing the username part of the authentication credentials + * @param[in] userid String containing the username to use to calculate the authentication digest (optional) + * @param[in] passwd String containing the password of the authentication credentials (optional, either passwd or ha1 must be set) + * @param[in] ha1 String containing a ha1 hash of the password (optional, either passwd or ha1 must be set) + * @param[in] realm String used to discriminate different SIP authentication domains (optional) + * @return #LinphoneAuthInfo with default values set + * @ingroup authentication + */ +LINPHONE_PUBLIC LinphoneAuthInfo * linphone_core_create_auth_info(LinphoneCore *lc, const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain); -void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); +LINPHONE_PUBLIC void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); -const MSList *linphone_core_get_auth_info_list(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info); -const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username); +LINPHONE_PUBLIC const MSList *linphone_core_get_auth_info_list(const LinphoneCore *lc); -void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *info); +LINPHONE_PUBLIC const LinphoneAuthInfo *linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *sip_domain); -void linphone_core_clear_all_auth_info(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_abort_authentication(LinphoneCore *lc, LinphoneAuthInfo *info); +LINPHONE_PUBLIC void linphone_core_clear_all_auth_info(LinphoneCore *lc); + +/** + * Enable or disable the audio adaptive jitter compensation. + * @param[in] lc #LinphoneCore object + * @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); +/** + * Tells whether the audio adaptive jitter compensation is enabled. + * @param[in] lc #LinphoneCore object + * @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); int linphone_core_get_audio_jittcomp(LinphoneCore *lc); void linphone_core_set_audio_jittcomp(LinphoneCore *lc, int value); +/** + * Enable or disable the video adaptive jitter compensation. + * @param[in] lc #LinphoneCore object + * @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); +/** + * Tells whether the video adaptive jitter compensation is enabled. + * @param[in] lc #LinphoneCore object + * @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); int linphone_core_get_video_jittcomp(LinphoneCore *lc); void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value); -int linphone_core_get_audio_port(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_audio_port(const LinphoneCore *lc); -void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port); +LINPHONE_PUBLIC void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port); -int linphone_core_get_video_port(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_video_port(const LinphoneCore *lc); -void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port); +LINPHONE_PUBLIC void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port); -int linphone_core_get_nortp_timeout(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_nortp_timeout(const LinphoneCore *lc); -void linphone_core_set_audio_port(LinphoneCore *lc, int port); +LINPHONE_PUBLIC void linphone_core_set_audio_port(LinphoneCore *lc, int port); -void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port); +LINPHONE_PUBLIC void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port); -void linphone_core_set_video_port(LinphoneCore *lc, int port); +LINPHONE_PUBLIC void linphone_core_set_video_port(LinphoneCore *lc, int port); -void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port); +LINPHONE_PUBLIC void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port); -void linphone_core_set_nortp_timeout(LinphoneCore *lc, int port); +LINPHONE_PUBLIC void linphone_core_set_nortp_timeout(LinphoneCore *lc, int port); -void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc, bool_t use_info); +LINPHONE_PUBLIC void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc, bool_t use_info); -bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc); -void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833); +LINPHONE_PUBLIC void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833); -bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc); -void linphone_core_set_sip_port(LinphoneCore *lc, int port); +LINPHONE_PUBLIC void linphone_core_set_sip_port(LinphoneCore *lc, int port); -int linphone_core_get_sip_port(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_sip_port(LinphoneCore *lc); -int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports *transports); +LINPHONE_PUBLIC int linphone_core_set_sip_transports(LinphoneCore *lc, const LCSipTransports *transports); -int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *transports); +LINPHONE_PUBLIC int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *transports); + +LINPHONE_PUBLIC bool_t linphone_core_sip_transport_supported(const LinphoneCore *lc, LinphoneTransportType tp); /** * * Give access to the UDP sip socket. Can be useful to configure this socket as persistent I.E kCFStreamNetworkServiceType set to kCFStreamNetworkServiceTypeVoIP) @@ -1179,21 +1568,33 @@ int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *transpor */ ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc); -void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds); +LINPHONE_PUBLIC void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds); -int linphone_core_get_inc_timeout(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_inc_timeout(LinphoneCore *lc); -void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds); +LINPHONE_PUBLIC void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds); -int linphone_core_get_in_call_timeout(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_in_call_timeout(LinphoneCore *lc); -void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds); +LINPHONE_PUBLIC void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds); -int linphone_core_get_delayed_timeout(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_delayed_timeout(LinphoneCore *lc); -void linphone_core_set_stun_server(LinphoneCore *lc, const char *server); +/** + * Set the STUN server address to use when the firewall policy is set to STUN. + * @param[in] lc #LinphoneCore object + * @param[in] server The STUN server address to use. + * @ingroup network_parameters + */ +LINPHONE_PUBLIC void linphone_core_set_stun_server(LinphoneCore *lc, const char *server); -const char * linphone_core_get_stun_server(const LinphoneCore *lc); +/** + * Get the STUN server address being used. + * @param[in] lc #LinphoneCore object + * @returns The STUN server address being used. + * @ingroup network_parameters + */ +LINPHONE_PUBLIC const char * linphone_core_get_stun_server(const LinphoneCore *lc); /** * @ingroup network_parameters @@ -1224,34 +1625,64 @@ LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc); */ 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. + * @param[in] lc #LinphoneCore object. + * @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); +/** + * Get the public IP address of NAT being used. + * @param[in] lc #LinphoneCore object. + * @returns The public IP address of NAT being used. + * @ingroup network_parameters + */ const char *linphone_core_get_nat_address(const LinphoneCore *lc); -void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol); +/** + * Set the policy to use to pass through firewalls. + * @param[in] lc #LinphoneCore object. + * @param[in] pol The #LinphoneFirewallPolicy to use. + * @ingroup network_parameters + */ +LINPHONE_PUBLIC void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol); -LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc); - -const char * linphone_core_get_relay_addr(const LinphoneCore *lc); - -int linphone_core_set_relay_addr(LinphoneCore *lc, const char *addr); +/** + * Get the policy that is used to pass through firewalls. + * @param[in] lc #LinphoneCore object. + * @returns The #LinphoneFirewallPolicy that is being used. + * @ingroup network_parameters + */ +LINPHONE_PUBLIC LinphoneFirewallPolicy linphone_core_get_firewall_policy(const LinphoneCore *lc); /* sound functions */ /* returns a null terminated static array of string describing the sound devices */ const char** linphone_core_get_sound_devices(LinphoneCore *lc); + +/** + * Update detection of sound devices. + * + * Use this function when the application is notified of USB plug events, so that + * list of available hardwares for sound playback and capture is updated. + * @param[in] lc #LinphoneCore object. + * @ingroup media_parameters + **/ 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); -int linphone_core_get_ring_level(LinphoneCore *lc); -int linphone_core_get_play_level(LinphoneCore *lc); +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); -void linphone_core_set_ring_level(LinphoneCore *lc, int level); -void linphone_core_set_play_level(LinphoneCore *lc, int level); +LINPHONE_PUBLIC void linphone_core_set_ring_level(LinphoneCore *lc, int level); +LINPHONE_PUBLIC void linphone_core_set_play_level(LinphoneCore *lc, int level); -void linphone_core_set_mic_gain_db(LinphoneCore *lc, float level); -float linphone_core_get_mic_gain_db(LinphoneCore *lc); -void linphone_core_set_playback_gain_db(LinphoneCore *lc, float level); -float linphone_core_get_playback_gain_db(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_mic_gain_db(LinphoneCore *lc, float level); +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); @@ -1262,35 +1693,68 @@ int linphone_core_set_playback_device(LinphoneCore *lc, const char * devid); 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); -void linphone_core_set_ring(LinphoneCore *lc, const char *path); -const char *linphone_core_get_ring(const LinphoneCore *lc); -void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno); -void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno); -void linphone_core_set_root_ca(LinphoneCore *lc, const char *path); -const char *linphone_core_get_root_ca(LinphoneCore *lc); -void linphone_core_set_ringback(LinphoneCore *lc, const char *path); -const char * linphone_core_get_ringback(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_stop_ringing(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_ring(LinphoneCore *lc, const char *path); +LINPHONE_PUBLIC const char *linphone_core_get_ring(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno); +LINPHONE_PUBLIC void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno); +LINPHONE_PUBLIC void linphone_core_set_root_ca(LinphoneCore *lc, const char *path); +LINPHONE_PUBLIC const char *linphone_core_get_root_ca(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_ringback(LinphoneCore *lc, const char *path); +LINPHONE_PUBLIC const char * linphone_core_get_ringback(const LinphoneCore *lc); -void linphone_core_set_remote_ringback_tone(LinphoneCore *lc,const char *); -const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_remote_ringback_tone(LinphoneCore *lc,const char *); +LINPHONE_PUBLIC const char *linphone_core_get_remote_ringback_tone(const LinphoneCore *lc); -int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata); -void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val); -bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCbFunc func,void * userdata); +LINPHONE_PUBLIC void linphone_core_enable_echo_cancellation(LinphoneCore *lc, bool_t val); +LINPHONE_PUBLIC bool_t linphone_core_echo_cancellation_enabled(LinphoneCore *lc); -void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val); -bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc); +/** + * Enables or disable echo limiter. + * @param[in] lc #LinphoneCore object. + * @param[in] val TRUE to enable echo limiter, FALSE to disable it. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val); + +/** + * Tells whether echo limiter is enabled. + * @param[in] lc #LinphoneCore object. + * @returns TRUE if the echo limiter is enabled, FALSE otherwise. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc); void linphone_core_enable_agc(LinphoneCore *lc, bool_t val); bool_t linphone_core_agc_enabled(const LinphoneCore *lc); -void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted); /** - * return mic state. - * + * @deprecated Use #linphone_core_enable_mic instead. +**/ +LINPHONE_PUBLIC void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted); + +/** + * Get mic state. + * @deprecated Use #linphone_core_is_mic_enabled instead +**/ +LINPHONE_PUBLIC bool_t linphone_core_is_mic_muted(LinphoneCore *lc); + +/** + * Enable or disable the microphone. + * @param[in] lc #LinphoneCore object + * @param[in] enable TRUE to enable the microphone, FALSE to disable it. * @ingroup media_parameters **/ -bool_t linphone_core_is_mic_muted(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_enable_mic(LinphoneCore *lc, bool_t enable); + +/** + * Tells whether the microphone is enabled. + * @param[in] lc #LinphoneCore object + * @returns TRUE if the microphone is enabled, FALSE if disabled. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_mic_enabled(LinphoneCore *lc); bool_t linphone_core_is_rtp_muted(LinphoneCore *lc); @@ -1299,63 +1763,186 @@ void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, bool_t val); /* returns a list of LinphoneCallLog */ -const MSList * linphone_core_get_call_logs(LinphoneCore *lc); -void linphone_core_clear_call_logs(LinphoneCore *lc); -int linphone_core_get_missed_calls_count(LinphoneCore *lc); -void linphone_core_reset_missed_calls_count(LinphoneCore *lc); -void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *call_log); +LINPHONE_PUBLIC const MSList * linphone_core_get_call_logs(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_clear_call_logs(LinphoneCore *lc); + +/** + * Get the number of missed calls. + * Once checked, this counter can be reset with linphone_core_reset_missed_calls_count(). + * @param[in] lc #LinphoneCore object. + * @returns The number of missed calls. + * @ingroup call_logs +**/ +LINPHONE_PUBLIC int linphone_core_get_missed_calls_count(LinphoneCore *lc); + +/** + * Reset the counter of missed calls. + * @param[in] lc #LinphoneCore object. + * @ingroup call_logs +**/ +LINPHONE_PUBLIC void linphone_core_reset_missed_calls_count(LinphoneCore *lc); + +/** + * Remove a specific call log from call history list. + * This function destroys the call log object. It must not be accessed anymore by the application after calling this function. + * @param[in] lc #LinphoneCore object + * @param[in] call_log #LinphoneCallLog object to remove. + * @ingroup call_logs +**/ +LINPHONE_PUBLIC void linphone_core_remove_call_log(LinphoneCore *lc, LinphoneCallLog *call_log); /* video support */ -bool_t linphone_core_video_supported(LinphoneCore *lc); -void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled); -bool_t linphone_core_video_enabled(LinphoneCore *lc); -void linphone_core_set_video_policy(LinphoneCore *lc, const LinphoneVideoPolicy *policy); -const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_video_supported(LinphoneCore *lc); + +/** + * Enables video globally. + * + * This function does not have any effect during calls. It just indicates LinphoneCore to + * initiate future calls with video or not. The two boolean parameters indicate in which + * direction video is enabled. Setting both to false disables video entirely. + * + * @param lc The LinphoneCore object + * @param vcap_enabled indicates whether video capture is enabled + * @param display_enabled indicates whether video display should be shown + * @ingroup media_parameters + * @deprecated Use #linphone_core_enable_video_capture and #linphone_core_enable_video_display instead. +**/ +LINPHONE_PUBLIC void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t display_enabled); + +/** + * Returns TRUE if video is enabled, FALSE otherwise. + * @ingroup media_parameters + * @deprecated Use #linphone_core_video_capture_enabled and #linphone_core_video_display_enabled instead. +**/ +LINPHONE_PUBLIC bool_t linphone_core_video_enabled(LinphoneCore *lc); + +/** + * Enable or disable video capture. + * + * This function does not have any effect during calls. It just indicates the #LinphoneCore to + * initiate future calls with video capture or not. + * @param[in] lc #LinphoneCore object. + * @param[in] enable TRUE to enable video capture, FALSE to disable it. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_enable_video_capture(LinphoneCore *lc, bool_t enable); + +/** + * Enable or disable video display. + * + * This function does not have any effect during calls. It just indicates the #LinphoneCore to + * initiate future calls with video display or not. + * @param[in] lc #LinphoneCore object. + * @param[in] enable TRUE to enable video display, FALSE to disable it. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_enable_video_display(LinphoneCore *lc, bool_t enable); + +/** + * Tells whether video capture is enabled. + * @param[in] lc #LinphoneCore object. + * @returns TRUE if video capture is enabled, FALSE if disabled. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_video_capture_enabled(LinphoneCore *lc); + +/** + * Tells whether video display is enabled. + * @param[in] lc #LinphoneCore object. + * @returns TRUE if video display is enabled, FALSE if disabled. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_core_video_display_enabled(LinphoneCore *lc); + +LINPHONE_PUBLIC void linphone_core_set_video_policy(LinphoneCore *lc, const LinphoneVideoPolicy *policy); +LINPHONE_PUBLIC const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc); typedef struct MSVideoSizeDef{ MSVideoSize vsize; const char *name; }MSVideoSizeDef; /* returns a zero terminated table of MSVideoSizeDef*/ -const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc); -void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize); -MSVideoSize linphone_core_get_preferred_video_size(LinphoneCore *lc); -void linphone_core_set_preferred_video_size_by_name(LinphoneCore *lc, const char *name); +LINPHONE_PUBLIC const MSVideoSizeDef *linphone_core_get_supported_video_sizes(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_preferred_video_size(LinphoneCore *lc, MSVideoSize vsize); +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); -void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val); -bool_t linphone_core_self_view_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); +/** + * Update detection of camera devices. + * + * Use this function when the application is notified of USB plug events, so that + * list of available hardwares for video capture is updated. + * @param[in] lc #LinphoneCore object. + * @ingroup media_parameters + **/ +void linphone_core_reload_video_devices(LinphoneCore *lc); + /* returns a null terminated static array of string describing the webcams */ -void linphone_core_reload_video_devices(LinphoneCore *lc); -const char** linphone_core_get_video_devices(const LinphoneCore *lc); -int linphone_core_set_video_device(LinphoneCore *lc, const char *id); -const char *linphone_core_get_video_device(const LinphoneCore *lc); +LINPHONE_PUBLIC const char** linphone_core_get_video_devices(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_set_video_device(LinphoneCore *lc, const char *id); +LINPHONE_PUBLIC const char *linphone_core_get_video_device(const LinphoneCore *lc); /* Set and get static picture to be used when "Static picture" is the video device */ +/** + * Set the path to the image file to stream when "Static picture" is set as the video device. + * @param[in] lc #LinphoneCore object. + * @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); + +/** + * Get the path to the image file streamed when "Static picture" is set as the video device. + * @param[in] lc #LinphoneCore object. + * @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); -/* Set and get frame rate for static picture */ +/** + * Set the frame rate for static picture. + * @param[in] lc #LinphoneCore object. + * @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); + +/** + * Get the frame rate for static picture + * @param[in] lc #LinphoneCore object. + * @return The frame rate used for static picture. + * @ingroup media_parameters + */ float linphone_core_get_static_picture_fps(LinphoneCore *lc); /*function to be used for eventually setting window decorations (icons, title...)*/ -unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc); -void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id); +LINPHONE_PUBLIC unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id); -unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc); -void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id); +LINPHONE_PUBLIC unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id); + +/** + * Tells the core to use a separate window for local camera preview video, instead of + * inserting local view within the remote video window. + * @param[in] lc #LinphoneCore object. + * @param[in] yesno TRUE to use a separate window, FALSE to insert the preview in the remote video window. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno); -void linphone_core_use_preview_window(LinphoneCore *lc, bool_t yesno); int linphone_core_get_device_rotation(LinphoneCore *lc ); void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation); /** - * @brief Get the camera sensor rotation. + * Get the camera sensor rotation. * * This is needed on some mobile platforms to get the number of degrees the camera sensor * is rotated relative to the screen. @@ -1363,24 +1950,24 @@ void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation); * @param lc The linphone core related to the operation * @return The camera sensor rotation in degrees (0 to 360) or -1 if it could not be retrieved */ -int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc); /* start or stop streaming video in case of embedded window */ 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); -void linphone_core_set_play_file(LinphoneCore *lc, const char *file); +LINPHONE_PUBLIC void linphone_core_set_play_file(LinphoneCore *lc, const char *file); void linphone_core_set_record_file(LinphoneCore *lc, const char *file); -void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms); -void linphone_core_stop_dtmf(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms); +LINPHONE_PUBLIC void linphone_core_stop_dtmf(LinphoneCore *lc); -int linphone_core_get_current_call_duration(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_current_call_duration(const LinphoneCore *lc); int linphone_core_get_mtu(const LinphoneCore *lc); -void linphone_core_set_mtu(LinphoneCore *lc, int mtu); +LINPHONE_PUBLIC void linphone_core_set_mtu(LinphoneCore *lc, int mtu); /** * @ingroup network_parameters @@ -1388,49 +1975,57 @@ void linphone_core_set_mtu(LinphoneCore *lc, int mtu); * Calling this method with true trigger linphone to initiate a registration process for all proxies. * Calling this method disables the automatic network detection mode. It means you must call this method after each network state changes. */ -void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value); +LINPHONE_PUBLIC void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t value); /** * @ingroup network_parameters * return network state either as positioned by the application or by linphone itself. */ -bool_t linphone_core_is_network_reachable(LinphoneCore* lc); +LINPHONE_PUBLIC bool_t linphone_core_is_network_reachable(LinphoneCore* lc); /** * @ingroup network_parameters * enable signaling keep alive. small udp packet sent periodically to keep udp NAT association */ -void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable); +LINPHONE_PUBLIC void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable); /** * @ingroup network_parameters * Is signaling keep alive */ -bool_t linphone_core_keep_alive_enabled(LinphoneCore* lc); +LINPHONE_PUBLIC bool_t linphone_core_keep_alive_enabled(LinphoneCore* lc); -void *linphone_core_get_user_data(LinphoneCore *lc); -void linphone_core_set_user_data(LinphoneCore *lc, void *userdata); +LINPHONE_PUBLIC void *linphone_core_get_user_data(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_user_data(LinphoneCore *lc, void *userdata); /* returns LpConfig object to read/write to the config file: usefull if you wish to extend the config file with your own sections */ -struct _LpConfig *linphone_core_get_config(LinphoneCore *lc); +LINPHONE_PUBLIC LpConfig * linphone_core_get_config(LinphoneCore *lc); + +/** + * Create a LpConfig object from a user config file. + * @param[in] lc #LinphoneCore object + * @param[in] filename The filename of the config file to read to fill the instantiated LpConfig + * @ingroup misc + */ +LINPHONE_PUBLIC LpConfig * linphone_core_create_lp_config(LinphoneCore *lc, const char *filename); /*set a callback for some blocking operations, it takes you informed of the progress of the operation*/ -void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneWaitingCallback cb, void *user_context); +void linphone_core_set_waiting_callback(LinphoneCore *lc, LinphoneCoreWaitingCallback cb, void *user_context); /*returns the list of registered SipSetup (linphonecore plugins) */ const MSList * linphone_core_get_sip_setups(LinphoneCore *lc); -void linphone_core_destroy(LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_destroy(LinphoneCore *lc); /*for advanced users:*/ -typedef RtpTransport * (*LinphoneRtpTransportFactoryFunc)(void *data, int port); +typedef RtpTransport * (*LinphoneCoreRtpTransportFactoryFunc)(void *data, int port); struct _LinphoneRtpTransportFactories{ - LinphoneRtpTransportFactoryFunc audio_rtp_func; + LinphoneCoreRtpTransportFactoryFunc audio_rtp_func; void *audio_rtp_func_data; - LinphoneRtpTransportFactoryFunc audio_rtcp_func; + LinphoneCoreRtpTransportFactoryFunc audio_rtcp_func; void *audio_rtcp_func_data; - LinphoneRtpTransportFactoryFunc video_rtp_func; + LinphoneCoreRtpTransportFactoryFunc video_rtp_func; void *video_rtp_func_data; - LinphoneRtpTransportFactoryFunc video_rtcp_func; + LinphoneCoreRtpTransportFactoryFunc video_rtcp_func; void *video_rtcp_func_data; }; typedef struct _LinphoneRtpTransportFactories LinphoneRtpTransportFactories; @@ -1439,20 +2034,33 @@ void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTran int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote); -int linphone_core_get_calls_nb(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_calls_nb(const LinphoneCore *lc); -const MSList *linphone_core_get_calls(LinphoneCore *lc); +LINPHONE_PUBLIC const MSList *linphone_core_get_calls(LinphoneCore *lc); LinphoneGlobalState linphone_core_get_global_state(const LinphoneCore *lc); /** * force registration refresh to be initiated upon next iterate * @ingroup proxies */ -void linphone_core_refresh_registers(LinphoneCore* lc); +LINPHONE_PUBLIC void linphone_core_refresh_registers(LinphoneCore* lc); -/* Path to the file storing secrets cache */ +/** + * Set the path to the file storing the zrtp secrets cache. + * @param[in] lc #LinphoneCore object + * @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); + +/** + * Get the path to the file storing the zrtp secrets cache. + * @param[in] lc #LinphoneCore object. + * @returns The path to the file storing the zrtp secrets cache. + * @ingroup initializing + */ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); + /** * Search from the list of current calls if a remote address match uri * @ingroup call_control @@ -1460,18 +2068,18 @@ const char *linphone_core_get_zrtp_secrets_file(LinphoneCore *lc); * @param uri which should match call remote uri * @return LinphoneCall or NULL is no match is found */ -LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri); +LINPHONE_PUBLIC LinphoneCall* linphone_core_find_call_from_uri(const LinphoneCore *lc, const char *uri); -int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call); -int linphone_core_add_all_to_conference(LinphoneCore *lc); -int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call); -bool_t linphone_core_is_in_conference(const LinphoneCore *lc); -int linphone_core_enter_conference(LinphoneCore *lc); -int linphone_core_leave_conference(LinphoneCore *lc); -float linphone_core_get_conference_local_input_volume(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_add_all_to_conference(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC bool_t linphone_core_is_in_conference(const LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_enter_conference(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_leave_conference(LinphoneCore *lc); +LINPHONE_PUBLIC float linphone_core_get_conference_local_input_volume(LinphoneCore *lc); -int linphone_core_terminate_conference(LinphoneCore *lc); -int linphone_core_get_conference_size(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_terminate_conference(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_conference_size(LinphoneCore *lc); int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path); int linphone_core_stop_conference_recording(LinphoneCore *lc); /** @@ -1480,61 +2088,83 @@ int linphone_core_stop_conference_recording(LinphoneCore *lc); * @param lc core * @return max number of simultaneous calls */ -int linphone_core_get_max_calls(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_get_max_calls(LinphoneCore *lc); /** * Set the maximum number of simultaneous calls Linphone core can manage at a time. All new call above this limit are declined with a busy answer * @ingroup initializing * @param lc core * @param max number of simultaneous calls */ -void linphone_core_set_max_calls(LinphoneCore *lc, int max); +LINPHONE_PUBLIC void linphone_core_set_max_calls(LinphoneCore *lc, int max); -bool_t linphone_core_sound_resources_locked(LinphoneCore *lc); +LINPHONE_PUBLIC bool_t linphone_core_sound_resources_locked(LinphoneCore *lc); -bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc); +LINPHONE_PUBLIC bool_t linphone_core_media_encryption_supported(const LinphoneCore *lc, LinphoneMediaEncryption menc); /** - * Choose media encryption policy to be used for RTP packets + * Choose the media encryption policy to be used for RTP packets. + * @param[in] lc #LinphoneCore object. + * @param[in] menc The media encryption policy to be used. + * @returns 0 if successful, any other value otherwise. + * @ingroup media_parameters */ -int linphone_core_set_media_encryption(LinphoneCore *lc, enum LinphoneMediaEncryption menc); -LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc); +LINPHONE_PUBLIC int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption menc); -bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc); /** - * Defines Linphone behaviour when encryption parameters negociation fails on outoing call. - * If set to TRUE call will fail; if set to FALSE will resend an INVITE with encryption disabled + * Get the media encryption policy being used for RTP packets. + * @param[in] lc #LinphoneCore object. + * @returns The media encryption policy being used. + * @ingroup media_parameters */ -void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m); +LINPHONE_PUBLIC LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc); + +/** + * Get behaviour when encryption parameters negociation fails on outgoing call. + * @param[in] lc #LinphoneCore object. + * @returns TRUE means the call will fail; FALSE means an INVITE will be resent with encryption disabled. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC bool_t linphone_core_is_media_encryption_mandatory(LinphoneCore *lc); + +/** + * Define behaviour when encryption parameters negociation fails on outgoing call. + * @param[in] lc #LinphoneCore object. + * @param[in] m If set to TRUE call will fail; if set to FALSE will resend an INVITE with encryption disabled. + * @ingroup media_parameters + */ +LINPHONE_PUBLIC void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m); /** * Init call params using LinphoneCore's current configuration */ -void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params); +LINPHONE_PUBLIC void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params); /** * True if tunnel support was compiled. */ -bool_t linphone_core_tunnel_available(void); +LINPHONE_PUBLIC bool_t linphone_core_tunnel_available(void); typedef struct _LinphoneTunnel LinphoneTunnel; /** * get tunnel instance if available */ -LinphoneTunnel *linphone_core_get_tunnel(LinphoneCore *lc); +LINPHONE_PUBLIC LinphoneTunnel *linphone_core_get_tunnel(LinphoneCore *lc); -void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp); -int linphone_core_get_sip_dscp(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp); +LINPHONE_PUBLIC int linphone_core_get_sip_dscp(const LinphoneCore *lc); -void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp); -int linphone_core_get_audio_dscp(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp); +LINPHONE_PUBLIC int linphone_core_get_audio_dscp(const LinphoneCore *lc); -void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp); -int linphone_core_get_video_dscp(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp); +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); #ifdef __cplusplus } #endif - #endif diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 19e5ff43d..65438fc19 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -48,19 +48,45 @@ extern "C" void libmssilk_init(); #ifdef HAVE_G729 extern "C" void libmsbcg729_init(); #endif +#ifdef HAVE_ISAC +extern "C" void libmsisac_init(); +#endif #endif /*ANDROID*/ + + +#define RETURN_USER_DATA_OBJECT(javaclass, funcprefix, cobj) \ + { \ + jclass jUserDataObjectClass; \ + jmethodID jUserDataObjectCtor; \ + jobject jUserDataObj; \ + jUserDataObj = (jobject)funcprefix ## _get_user_data(cobj); \ + if (jUserDataObj == NULL) { \ + jUserDataObjectClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/" javaclass)); \ + jUserDataObjectCtor = env->GetMethodID(jUserDataObjectClass,"", "(J)V"); \ + jUserDataObj = env->NewObject(jUserDataObjectClass, jUserDataObjectCtor, (jlong)funcprefix ## _ref(cobj)); \ + jUserDataObj = env->NewGlobalRef(jUserDataObj); \ + funcprefix ## _set_user_data(cobj, jUserDataObj); \ + env->DeleteGlobalRef(jUserDataObjectClass); \ + } \ + return jUserDataObj; \ + } + + + static JavaVM *jvm=0; static const char* LogDomain = "Linphone"; +static jclass handler_class; +static jmethodID loghandler_id; +static jobject handler_obj=NULL; + +static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *content); #ifdef ANDROID -void linphone_android_log_handler(int prio, const char *fmt, va_list args) { - char str[4096]; +void linphone_android_log_handler(int prio, char *str) { char *current; char *next; - vsnprintf(str, sizeof(str) - 1, fmt, args); - str[sizeof(str) - 1] = '\0'; if (strlen(str) < 512) { __android_log_write(prio, LogDomain, str); } else { @@ -75,16 +101,25 @@ void linphone_android_log_handler(int prio, const char *fmt, va_list args) { } static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt, va_list args) { + char str[4096]; + const char *levname="undef"; + vsnprintf(str, sizeof(str) - 1, fmt, args); + str[sizeof(str) - 1] = '\0'; + int prio; switch(lev){ - case ORTP_DEBUG: prio = ANDROID_LOG_DEBUG; break; - case ORTP_MESSAGE: prio = ANDROID_LOG_INFO; break; - case ORTP_WARNING: prio = ANDROID_LOG_WARN; break; - case ORTP_ERROR: prio = ANDROID_LOG_ERROR; break; - case ORTP_FATAL: prio = ANDROID_LOG_FATAL; break; - default: prio = ANDROID_LOG_DEFAULT; break; + case ORTP_DEBUG: prio = ANDROID_LOG_DEBUG; levname="debug"; break; + case ORTP_MESSAGE: prio = ANDROID_LOG_INFO; levname="message"; break; + case ORTP_WARNING: prio = ANDROID_LOG_WARN; levname="warning"; break; + case ORTP_ERROR: prio = ANDROID_LOG_ERROR; levname="error"; break; + case ORTP_FATAL: prio = ANDROID_LOG_FATAL; levname="fatal"; break; + default: prio = ANDROID_LOG_DEFAULT; break; } - linphone_android_log_handler(prio, fmt, args); + if (handler_obj){ + JNIEnv *env=ms_get_jni_env(); + env->CallVoidMethod(handler_obj,loghandler_id,env->NewStringUTF(LogDomain),(jint)lev,env->NewStringUTF(levname),env->NewStringUTF(str),NULL); + }else + linphone_android_log_handler(prio, str); } int dumbMethodForAllowingUsageOfCpuFeaturesFromStaticLibMediastream() { @@ -136,9 +171,14 @@ public: vTable.text_received = text_received; vTable.message_received = message_received; vTable.dtmf_received = dtmf_received; - vTable.new_subscription_request = new_subscription_request; - vTable.notify_presence_recv = notify_presence_recv; + vTable.new_subscription_requested = new_subscription_requested; + vTable.notify_presence_received = notify_presence_received; vTable.call_stats_updated = callStatsUpdated; + vTable.transfer_state_changed = transferStateChanged; + vTable.info_received = infoReceived; + vTable.subscription_state_changed=subscriptionStateChanged; + vTable.notify_received=notifyReceived; + vTable.publish_state_changed=publishStateChanged; listenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener)); @@ -160,6 +200,8 @@ public: callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State")); callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;"); + transferStateId = env->GetMethodID(listenerClass,"transferState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;)V"); + /*callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);*/ callStatsUpdatedId = env->GetMethodID(listenerClass, "callStatsUpdated", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCallStats;)V"); @@ -184,7 +226,17 @@ public: 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"); 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"); + subscriptionStateId = env->GetMethodID(listenerClass,"subscriptionStateChanged", + "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/SubscriptionState;)V"); + publishStateId = env->GetMethodID(listenerClass,"publishStateChanged", + "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/PublishState;)V"); + notifyRecvId = env->GetMethodID(listenerClass,"notifyReceived", + "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Ljava/lang/String;Lorg/linphone/core/LinphoneContent;)V"); + + proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl")); proxyCtrId = env->GetMethodID(proxyClass,"", "(J)V"); @@ -207,6 +259,21 @@ public: callStatsId = env->GetMethodID(callStatsClass, "", "(JJ)V"); callSetAudioStatsId = env->GetMethodID(callClass, "setAudioStats", "(Lorg/linphone/core/LinphoneCallStats;)V"); callSetVideoStatsId = env->GetMethodID(callClass, "setVideoStats", "(Lorg/linphone/core/LinphoneCallStats;)V"); + + infoMessageClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneInfoMessageImpl")); + infoMessageCtor = env->GetMethodID(infoMessageClass,"", "(J)V"); + + linphoneEventClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneEventImpl")); + linphoneEventCtrId = env->GetMethodID(linphoneEventClass,"", "(J)V"); + + subscriptionStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionState")); + subscriptionStateFromIntId = env->GetStaticMethodID(subscriptionStateClass,"fromInt","(I)Lorg/linphone/core/SubscriptionState;"); + + publishStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/PublishState")); + publishStateFromIntId = env->GetStaticMethodID(publishStateClass,"fromInt","(I)Lorg/linphone/core/PublishState;"); + + subscriptionDirClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionDir")); + subscriptionDirFromIntId = env->GetStaticMethodID(subscriptionDirClass,"fromInt","(I)Lorg/linphone/core/SubscriptionDir;"); } ~LinphoneCoreData() { @@ -219,14 +286,16 @@ public: env->DeleteGlobalRef(globalStateClass); env->DeleteGlobalRef(registrationStateClass); env->DeleteGlobalRef(callStateClass); - env->DeleteGlobalRef(callStatsClass); env->DeleteGlobalRef(chatMessageStateClass); env->DeleteGlobalRef(proxyClass); env->DeleteGlobalRef(callClass); env->DeleteGlobalRef(chatMessageClass); env->DeleteGlobalRef(chatRoomClass); env->DeleteGlobalRef(friendClass); - + env->DeleteGlobalRef(infoMessageClass); + env->DeleteGlobalRef(linphoneEventClass); + env->DeleteGlobalRef(subscriptionStateClass); + env->DeleteGlobalRef(subscriptionDirClass); } jobject core; jobject listener; @@ -240,6 +309,11 @@ public: jmethodID messageReceivedId; jmethodID dtmfReceivedId; jmethodID callStatsUpdatedId; + jmethodID transferStateId; + jmethodID infoReceivedId; + jmethodID subscriptionStateId; + jmethodID publishStateId; + jmethodID notifyRecvId; jclass globalStateClass; jmethodID globalStateId; @@ -284,6 +358,21 @@ public: jclass addressClass; jmethodID addressCtrId; + + jclass infoMessageClass; + jmethodID infoMessageCtor; + + jclass linphoneEventClass; + jmethodID linphoneEventCtrId; + + jclass subscriptionStateClass; + jmethodID subscriptionStateFromIntId; + + jclass publishStateClass; + jmethodID publishStateFromIntId; + + jclass subscriptionDirClass; + jmethodID subscriptionDirFromIntId; LinphoneCoreVTable vTable; @@ -297,7 +386,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -306,14 +395,14 @@ public: static void displayMessageCb(LinphoneCore *lc, const char *message) { } - static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username) { + static void authInfoRequested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { } static void globalStateChange(LinphoneCore *lc, LinphoneGlobalState gstate,const char* message) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -327,7 +416,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -361,7 +450,7 @@ public: jint result = jvm->AttachCurrentThread(&env,NULL); jobject jcall; if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -380,7 +469,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -391,11 +480,11 @@ public: ,encrypted ,authentication_token ? env->NewStringUTF(authentication_token) : NULL); } - static void notify_presence_recv (LinphoneCore *lc, LinphoneFriend *my_friend) { + static void notify_presence_received(LinphoneCore *lc, LinphoneFriend *my_friend) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -404,11 +493,11 @@ public: ,lcData->core ,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)my_friend)); } - static void new_subscription_request (LinphoneCore *lc, LinphoneFriend *my_friend, const char* url) { + static void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *my_friend, const char* url) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -422,7 +511,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -436,7 +525,7 @@ public: JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -447,11 +536,11 @@ public: ,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)from) ,message ? env->NewStringUTF(message) : NULL); } - static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { + static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *msg) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -459,13 +548,13 @@ public: ,lcData->messageReceivedId ,lcData->core ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room) - ,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg)); + ,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg)); } static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) { JNIEnv *env = 0; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -487,7 +576,7 @@ public: jobject callobj; jint result = jvm->AttachCurrentThread(&env,NULL); if (result != 0) { - ms_error("cannot attach VM\n"); + ms_error("cannot attach VM"); return; } LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); @@ -499,9 +588,112 @@ public: env->CallVoidMethod(callobj, lcData->callSetVideoStatsId, statsobj); env->CallVoidMethod(lcData->listener, lcData->callStatsUpdatedId, lcData->core, callobj, statsobj); } - - + static void transferStateChanged(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState remote_call_state){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jcall; + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod(lcData->listener + ,lcData->transferStateId + ,lcData->core + ,(jcall=lcData->getCall(env,call)) + ,env->CallStaticObjectMethod(lcData->callStateClass,lcData->callStateFromIntId,(jint)remote_call_state) + ); + } + static void infoReceived(LinphoneCore *lc, LinphoneCall*call, const LinphoneInfoMessage *info){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jcall; + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneInfoMessage *copy_info=linphone_info_message_copy(info); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + env->CallVoidMethod(lcData->listener + ,lcData->infoReceivedId + ,lcData->core + ,lcData->getCall(env,call) + ,env->NewObject(lcData->infoMessageClass,lcData->infoMessageCtor,(jlong)copy_info) + ); + } + jobject getEvent(JNIEnv *env, LinphoneEvent *lev){ + if (lev==NULL) return NULL; + jobject jev=(jobject)linphone_event_get_user_data(lev); + if (jev==NULL){ + jev=env->NewObject(linphoneEventClass,linphoneEventCtrId,(jlong)linphone_event_ref(lev)); + jev=env->NewGlobalRef(jev); + linphone_event_set_user_data(lev,jev); + } + return jev; + } + static void subscriptionStateChanged(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jevent; + jobject jstate; + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + jevent=lcData->getEvent(env,ev); + jstate=env->CallStaticObjectMethod(lcData->subscriptionStateClass,lcData->subscriptionStateFromIntId,(jint)state); + env->CallVoidMethod(lcData->listener + ,lcData->subscriptionStateId + ,lcData->core + ,jevent + ,jstate + ); + if (state==LinphoneSubscriptionTerminated){ + /*loose the java reference */ + linphone_event_set_user_data(ev,NULL); + env->DeleteGlobalRef(jevent); + } + } + static void publishStateChanged(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jevent; + jobject jstate; + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + jevent=lcData->getEvent(env,ev); + jstate=env->CallStaticObjectMethod(lcData->publishStateClass,lcData->publishStateFromIntId,(jint)state); + env->CallVoidMethod(lcData->listener + ,lcData->publishStateId + ,lcData->core + ,jevent + ,jstate + ); + } + static void notifyReceived(LinphoneCore *lc, LinphoneEvent *ev, const char *evname, const LinphoneContent *content){ + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + jobject jevent; + if (result != 0) { + ms_error("cannot attach VM"); + return; + } + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + jevent=lcData->getEvent(env,ev); + env->CallVoidMethod(lcData->listener + ,lcData->notifyRecvId + ,lcData->core + ,jevent + ,env->NewStringUTF(evname) + ,content ? create_java_linphone_content(env,content) : NULL + ); + } }; + extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* env ,jobject thiz ,jobject jlistener @@ -528,11 +720,16 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* #ifdef HAVE_G729 libmsbcg729_init(); #endif +#ifdef HAVE_ISAC + libmsisac_init(); +#endif + jlong nativePtr = (jlong)linphone_core_new( &ldata->vTable ,userConfig ,factoryConfig ,ldata); + if (userConfig) env->ReleaseStringUTFChars(juserConfig, userConfig); if (factoryConfig) env->ReleaseStringUTFChars(jfactoryConfig, factoryConfig); return nativePtr; @@ -545,6 +742,25 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv* env delete lcData; } +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: createInfoMessage + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_LinphoneCoreImpl_createInfoMessage(JNIEnv *, jobject jobj, jlong lcptr){ + return (jlong) linphone_core_create_info_message((LinphoneCore*)lcptr); +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCallImpl_sendInfoMessage(JNIEnv *env, jobject jobj, jlong callptr, jlong infoptr){ + return linphone_call_send_info_message((LinphoneCall*)callptr,(LinphoneInfoMessage*)infoptr); +} + +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); + env->ReleaseStringUTFChars(jpath, path); +} + 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); @@ -561,6 +777,18 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPrimaryContact(JNIEnv env->ReleaseStringUTFChars(jusername, username); } +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getPrimaryContactUsername(JNIEnv* env, jobject thiz, jlong lc) { + LinphoneAddress* identity = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc); + const char * username = linphone_address_get_username(identity); + return username ? env->NewStringUTF(username) : NULL; +} + +extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getPrimaryContactDisplayName(JNIEnv* env, jobject thiz, jlong lc) { + LinphoneAddress* identity = linphone_core_get_primary_contact_parsed((LinphoneCore*)lc); + const char * displayname = linphone_address_get_display_name(identity); + return displayname ? env->NewStringUTF(displayname) : NULL; +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearProxyConfigs(JNIEnv* env, jobject thiz,jlong lc) { linphone_core_clear_proxy_config((LinphoneCore*)lc); } @@ -580,7 +808,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getDefaultProxyConfig( } extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getProxyConfigList(JNIEnv* env, jobject thiz, jlong lc) { - const MSList* proxies = linphone_core_get_proxy_config_list((LinphoneCore*)lc); + const MSList* proxies = linphone_core_get_proxy_config_list((LinphoneCore*)lc); int proxyCount = ms_list_size(proxies); jlongArray jProxies = env->NewLongArray(proxyCount); jlong *jInternalArray = env->GetLongArrayElements(jProxies, NULL); @@ -606,6 +834,45 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig( JNIEnv* return (jint)linphone_core_add_proxy_config((LinphoneCore*)lc,(LinphoneProxyConfig*)pc); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeProxyConfig(JNIEnv* env, jobject thiz, jlong lc, jlong proxy) { + linphone_core_remove_proxy_config((LinphoneCore*)lc, (LinphoneProxyConfig*)proxy); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeAuthInfo(JNIEnv* env, jobject thiz, jlong lc, jlong authInfo) { + linphone_core_remove_auth_info((LinphoneCore*)lc, (LinphoneAuthInfo*)authInfo); +} + +extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getAuthInfosList(JNIEnv* env, jobject thiz,jlong lc) { + const MSList* authInfos = linphone_core_get_auth_info_list((LinphoneCore*)lc); + int listCount = ms_list_size(authInfos); + jlongArray jAuthInfos = env->NewLongArray(listCount); + jlong *jInternalArray = env->GetLongArrayElements(jAuthInfos, NULL); + + for (int i = 0; i < listCount; i++ ) { + jInternalArray[i] = (unsigned long) (authInfos->data); + authInfos = authInfos->next; + } + + env->ReleaseLongArrayElements(jAuthInfos, jInternalArray, 0); + + return jAuthInfos; +} + +extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_findAuthInfos(JNIEnv* env, jobject thiz, jlong lc, jstring jusername, jstring jrealm, jstring jdomain) { + const char* username = env->GetStringUTFChars(jusername, NULL); + const char* realm = jrealm ? env->GetStringUTFChars(jrealm, NULL) : NULL; + const char* domain = jdomain ? env->GetStringUTFChars(jdomain, NULL) : NULL; + const LinphoneAuthInfo *authInfo = linphone_core_find_auth_info((LinphoneCore*)lc, realm, username, domain); + + if (realm) + env->ReleaseStringUTFChars(jrealm, realm); + if (domain) + env->ReleaseStringUTFChars(jdomain, domain); + env->ReleaseStringUTFChars(jusername, username); + + return (jlong) authInfo; +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearAuthInfos(JNIEnv* env, jobject thiz,jlong lc) { linphone_core_clear_all_auth_info((LinphoneCore*)lc); } @@ -614,18 +881,18 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_refreshRegisters(JNIEnv* linphone_core_refresh_registers((LinphoneCore*)lc); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addAuthInfo( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addAuthInfo(JNIEnv* env ,jobject thiz ,jlong lc ,jlong pc) { linphone_core_add_auth_info((LinphoneCore*)lc,(LinphoneAuthInfo*)pc); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_iterate( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_iterate(JNIEnv* env ,jobject thiz ,jlong lc) { linphone_core_iterate((LinphoneCore*)lc); } -extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_invite( JNIEnv* env +extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_invite(JNIEnv* env ,jobject thiz ,jlong lc ,jstring juri) { @@ -635,7 +902,7 @@ extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_invite( JNIEnv* env env->ReleaseStringUTFChars(juri, uri); return lcd->getCall(env,lCall); } -extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_inviteAddress( JNIEnv* env +extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_inviteAddress(JNIEnv* env ,jobject thiz ,jlong lc ,jlong to) { @@ -643,38 +910,38 @@ extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_inviteAddress( JNIEnv return lcd->getCall(env, linphone_core_invite_address((LinphoneCore*)lc,(LinphoneAddress*)to)); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateCall( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateCall(JNIEnv* env ,jobject thiz ,jlong lc ,jlong call) { linphone_core_terminate_call((LinphoneCore*)lc,(LinphoneCall*)call); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_declineCall( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_declineCall(JNIEnv* env ,jobject thiz ,jlong lc ,jlong call, jint reason) { linphone_core_decline_call((LinphoneCore*)lc,(LinphoneCall*)call,(LinphoneReason)reason); } -extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getRemoteAddress( JNIEnv* env +extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getRemoteAddress(JNIEnv* env ,jobject thiz ,jlong lc) { return (jlong)linphone_core_get_current_call_remote_address((LinphoneCore*)lc); } -extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInCall( JNIEnv* env +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInCall(JNIEnv* env ,jobject thiz ,jlong lc) { return (jboolean)linphone_core_in_call((LinphoneCore*)lc); } -extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInComingInvitePending( JNIEnv* env +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInComingInvitePending(JNIEnv* env ,jobject thiz ,jlong lc) { return (jboolean)linphone_core_inc_invite_pending((LinphoneCore*)lc); } -extern "C" void Java_org_linphone_core_LinphoneCoreImpl_acceptCall( JNIEnv* env +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_acceptCall(JNIEnv* env ,jobject thiz ,jlong lc ,jlong call) { @@ -836,7 +1103,7 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listVideoPayloadTy codecs = codecs->next; } - env->ReleaseLongArrayElements(jCodecs, jInternalArray, 0); + env->ReleaseLongArrayElements(jCodecs, jInternalArray, 0); return jCodecs; } @@ -866,6 +1133,12 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_enablePayloadType(JNIEnv ,jboolean enable) { return (jint)linphone_core_enable_payload_type((LinphoneCore*)lc,(PayloadType*)pt,enable); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isPayloadTypeEnabled(JNIEnv* env + ,jobject thiz + ,jlong lc + ,jlong pt) { + return (jboolean) linphone_core_payload_type_enabled((LinphoneCore*)lc, (PayloadType*)pt); +} extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableEchoCancellation(JNIEnv* env ,jobject thiz ,jlong lc @@ -910,21 +1183,47 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addFriend(JNIEnv* env extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPresenceInfo(JNIEnv* env ,jobject thiz ,jlong lc - ,jint minute_away + ,jint minutes_away ,jstring jalternative_contact ,jint status) { const char* alternative_contact = jalternative_contact?env->GetStringUTFChars(jalternative_contact, NULL):NULL; - linphone_core_set_presence_info((LinphoneCore*)lc,minute_away,alternative_contact,(LinphoneOnlineStatus)status); + linphone_core_set_presence_info((LinphoneCore*)lc,minutes_away,alternative_contact,(LinphoneOnlineStatus)status); if (alternative_contact) env->ReleaseStringUTFChars(jalternative_contact, alternative_contact); } +extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getPresenceInfo(JNIEnv *env, jobject thiz, jlong lc) { + return (jint)linphone_core_get_presence_info((LinphoneCore *)lc); +} -extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createChatRoom(JNIEnv* env +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: setPresenceModel + * Signature: (JILjava/lang/String;J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_setPresenceModel(JNIEnv *env, jobject jobj, jlong ptr, jlong modelPtr) { + LinphoneCore *lc = (LinphoneCore *)ptr; + LinphonePresenceModel *model = (LinphonePresenceModel *)modelPtr; + linphone_core_set_presence_model(lc, model); +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: getPresenceModel + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_getPresenceModel(JNIEnv *env, jobject jobj, jlong ptr) { + LinphoneCore *lc = (LinphoneCore *)ptr; + LinphonePresenceModel *model = linphone_core_get_presence_model(lc); + if (model == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceModelImpl", linphone_presence_model, model) +} + +extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getOrCreateChatRoom(JNIEnv* env ,jobject thiz ,jlong lc ,jstring jto) { const char* to = env->GetStringUTFChars(jto, NULL); - LinphoneChatRoom* lResult = linphone_core_create_chat_room((LinphoneCore*)lc,to); + LinphoneChatRoom* lResult = linphone_core_get_or_create_chat_room((LinphoneCore*)lc,to); env->ReleaseStringUTFChars(jto, to); return (jlong)lResult; } @@ -942,6 +1241,14 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isVideoEnabled(JNIEn ,jlong lc) { return (jboolean)linphone_core_video_enabled((LinphoneCore*)lc); } + +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isVideoSupported(JNIEnv* env + ,jobject thiz + ,jlong lc) { + return (jboolean)linphone_core_video_supported((LinphoneCore*)lc); +} + + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPlayFile(JNIEnv* env ,jobject thiz ,jlong lc @@ -1011,7 +1318,9 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCalibration ms_error("Could not get soundcard."); return TRUE; } - return (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) || (ms_snd_card_get_minimal_latency(sndcard)>0); + if (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) return FALSE; + if (ms_snd_card_get_minimal_latency(sndcard)==0) return TRUE; + return FALSE; } extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv* env @@ -1164,10 +1473,15 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getDomain(JNIE return NULL; } } + extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setDialEscapePlus(JNIEnv* env,jobject thiz,jlong proxyCfg,jboolean value) { linphone_proxy_config_set_dial_escape_plus((LinphoneProxyConfig*)proxyCfg,value); } +extern "C" jboolean Java_org_linphone_core_LinphoneProxyConfigImpl_getDialEscapePlus(JNIEnv* env,jobject thiz,jlong proxyCfg) { + return (jboolean) linphone_proxy_config_get_dial_escape_plus((LinphoneProxyConfig*)proxyCfg); +} + extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setDialPrefix(JNIEnv* env ,jobject thiz ,jlong proxyCfg @@ -1176,6 +1490,12 @@ extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setDialPrefix(JNI linphone_proxy_config_set_dial_prefix((LinphoneProxyConfig*)proxyCfg,prefix); env->ReleaseStringUTFChars(jprefix, prefix); } + +extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getDialPrefix(JNIEnv* env,jobject thiz,jlong proxyCfg) { + const char * prefix = linphone_proxy_config_get_dial_prefix((LinphoneProxyConfig*)proxyCfg); + return prefix ? env->NewStringUTF(prefix) : NULL; +} + extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_enablePublish(JNIEnv* env ,jobject thiz ,jlong proxyCfg @@ -1186,11 +1506,15 @@ extern "C" jboolean Java_org_linphone_core_LinphoneProxyConfigImpl_publishEnable return (jboolean)linphone_proxy_config_publish_enabled((LinphoneProxyConfig*)proxyCfg); } +extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getError(JNIEnv* env,jobject thiz,jlong ptr) { + return linphone_proxy_config_get_error((LinphoneProxyConfig *) ptr); +} + //Auth Info extern "C" jlong Java_org_linphone_core_LinphoneAuthInfoImpl_newLinphoneAuthInfo(JNIEnv* env , jobject thiz ) { - return (jlong)linphone_auth_info_new(NULL,NULL,NULL,NULL,NULL); + return (jlong)linphone_auth_info_new(NULL,NULL,NULL,NULL,NULL,NULL); } extern "C" void Java_org_linphone_core_LinphoneAuthInfoImpl_delete(JNIEnv* env , jobject thiz @@ -1210,7 +1534,6 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getPasswor } else { return NULL; } - } /* * Class: org_linphone_core_LinphoneAuthInfoImpl @@ -1225,7 +1548,21 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getRealm } else { return NULL; } +} +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: getDomain + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_getDomain +(JNIEnv *env , jobject, jlong auth_info) { + const char* domain = linphone_auth_info_get_domain((LinphoneAuthInfo*)auth_info); + if (domain) { + return env->NewStringUTF(domain); + } else { + return NULL; + } } /* @@ -1266,6 +1603,20 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_setRealm linphone_auth_info_set_realm((LinphoneAuthInfo*)auth_info,realm); if (realm) env->ReleaseStringUTFChars(jrealm, realm); } + +/* + * Class: org_linphone_core_LinphoneAuthInfoImpl + * Method: setDomain + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneAuthInfoImpl_setDomain +(JNIEnv *env, jobject, jlong auth_info, jstring jdomain) { + const char* domain = jdomain ? env->GetStringUTFChars(jdomain, NULL) : NULL; + linphone_auth_info_set_domain((LinphoneAuthInfo*)auth_info, domain); + if (domain) + env->ReleaseStringUTFChars(jdomain, domain); +} + /* * Class: org_linphone_core_LinphoneAuthInfoImpl * Method: setUsername @@ -1340,21 +1691,34 @@ extern "C" jlong Java_org_linphone_core_LinphoneAddressImpl_newLinphoneAddressIm ,jobject thiz ,jstring juri ,jstring jdisplayName) { - const char* uri = env->GetStringUTFChars(juri, NULL); + const char* uri = juri?env->GetStringUTFChars(juri, NULL):NULL; LinphoneAddress* address = linphone_address_new(uri); if (jdisplayName && address) { const char* displayName = env->GetStringUTFChars(jdisplayName, NULL); linphone_address_set_display_name(address,displayName); env->ReleaseStringUTFChars(jdisplayName, displayName); } - env->ReleaseStringUTFChars(juri, uri); + if (uri) env->ReleaseStringUTFChars(juri, uri); return (jlong) address; } -extern "C" void Java_org_linphone_core_LinphoneAddressImpl_delete(JNIEnv* env + +extern "C" jlong Java_org_linphone_core_LinphoneAddressImpl_ref(JNIEnv* env ,jobject thiz ,jlong ptr) { - linphone_address_destroy((LinphoneAddress*)ptr); + return (jlong)linphone_address_ref((LinphoneAddress*)ptr); +} + +extern "C" jlong Java_org_linphone_core_LinphoneAddressImpl_clone(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jlong) (ptr ? linphone_address_clone((const LinphoneAddress*)ptr) : NULL); +} + +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_unref(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_address_unref((LinphoneAddress*)ptr); } extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDisplayName(JNIEnv* env @@ -1387,14 +1751,6 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv* return NULL; } } -extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDomain(JNIEnv* env - ,jobject thiz - ,jlong ptr - ,jstring jdomain) { - const char* domain = env->GetStringUTFChars(jdomain, NULL); - linphone_address_set_domain((LinphoneAddress*)ptr, domain); - env->ReleaseStringUTFChars(jdomain, domain); -} extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_toString(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -1419,6 +1775,22 @@ extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDisplayName(JNIEnv linphone_address_set_display_name((LinphoneAddress*)address,displayName); if (displayName != NULL) env->ReleaseStringUTFChars(jdisplayName, displayName); } +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setUserName(JNIEnv* env + ,jobject thiz + ,jlong address + ,jstring juserName) { + const char* userName = juserName!= NULL?env->GetStringUTFChars(juserName, NULL):NULL; + linphone_address_set_username((LinphoneAddress*)address,userName); + if (userName != NULL) env->ReleaseStringUTFChars(juserName, userName); +} +extern "C" void Java_org_linphone_core_LinphoneAddressImpl_setDomain(JNIEnv* env + ,jobject thiz + ,jlong address + ,jstring jdomain) { + const char* domain = jdomain!= NULL?env->GetStringUTFChars(jdomain, NULL):NULL; + linphone_address_set_domain((LinphoneAddress*)address,domain); + if (domain != NULL) env->ReleaseStringUTFChars(jdomain, domain); +} //CallLog @@ -1685,6 +2057,43 @@ extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getState( JNIEnv* env ,jlong ptr) { return (jint)linphone_call_get_state((LinphoneCall*)ptr); } + +/* + * Class: org_linphone_core_LinphoneCallImpl + * Method: getTransferState + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneCallImpl_getTransferState(JNIEnv *, jobject jobj, jlong callptr){ + LinphoneCall *call=(LinphoneCall*)callptr; + return linphone_call_get_transfer_state(call); +} + +/* + * Class: org_linphone_core_LinphoneCallImpl + * Method: getTransfererCall + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCallImpl_getTransfererCall(JNIEnv *env, jobject jCall, jlong callptr){ + LinphoneCall *call=(LinphoneCall*)callptr; + LinphoneCore *lc=linphone_call_get_core(call); + LinphoneCoreData *lcdata=(LinphoneCoreData*)linphone_core_get_user_data(lc); + LinphoneCall *ret=linphone_call_get_transferer_call(call); + return lcdata->getCall(env,ret); +} + +/* + * Class: org_linphone_core_LinphoneCallImpl + * Method: getTransferTargetCall + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCallImpl_getTransferTargetCall(JNIEnv *env, jobject jCall, jlong callptr){ + LinphoneCall *call=(LinphoneCall*)callptr; + LinphoneCore *lc=linphone_call_get_core(call); + LinphoneCoreData *lcdata=(LinphoneCoreData*)linphone_core_get_user_data(lc); + LinphoneCall *ret=linphone_call_get_transfer_target_call(call); + return lcdata->getCall(env,ret); +} + extern "C" void Java_org_linphone_core_LinphoneCallImpl_enableEchoCancellation( JNIEnv* env ,jobject thiz ,jlong ptr @@ -1736,7 +2145,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNI if (jFriendUri) { const char* friendUri = env->GetStringUTFChars(jFriendUri, NULL); - lResult= linphone_friend_new_with_addr(friendUri); + lResult= linphone_friend_new_with_address(friendUri); env->ReleaseStringUTFChars(jFriendUri, friendUri); } else { lResult = linphone_friend_new(); @@ -1747,7 +2156,7 @@ extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setAddress(JNIEnv* en ,jobject thiz ,jlong ptr ,jlong linphoneAddress) { - linphone_friend_set_addr((LinphoneFriend*)ptr,(LinphoneAddress*)linphoneAddress); + linphone_friend_set_address((LinphoneFriend*)ptr,(LinphoneAddress*)linphoneAddress); } extern "C" jlong Java_org_linphone_core_LinphoneFriendImpl_getAddress(JNIEnv* env ,jobject thiz @@ -1781,6 +2190,19 @@ extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv* env ,jlong ptr) { return (jint)linphone_friend_get_status((LinphoneFriend*)ptr); } + +/* + * Class: org_linphone_core_LinphoneFriendImpl + * Method: getPresenceModel + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneFriendImpl_getPresenceModel(JNIEnv *env, jobject jobj, jlong ptr) { + LinphoneFriend *lf = (LinphoneFriend *)ptr; + LinphonePresenceModel *model = (LinphonePresenceModel *)linphone_friend_get_presence_model(lf); + if (model == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceModelImpl", linphone_presence_model, model); +} + extern "C" void Java_org_linphone_core_LinphoneFriendImpl_edit(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -1807,6 +2229,24 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getFriendByAddress(JNIE return (jlong) lf; } //LinphoneChatRoom +extern "C" jlongArray Java_org_linphone_core_LinphoneChatRoomImpl_getHistory(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jint limit) { + MSList* history = linphone_chat_room_get_history((LinphoneChatRoom*)ptr, limit); + int historySize = ms_list_size(history); + jlongArray jHistory = env->NewLongArray(historySize); + jlong *jInternalArray = env->GetLongArrayElements(jHistory, NULL); + + for (int i = 0; i < historySize; i++) { + jInternalArray[i] = (unsigned long) (history->data); + history = history->next; + } + + env->ReleaseLongArrayElements(jHistory, jInternalArray, 0); + + return jHistory; +} extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_getPeerAddress(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -1822,12 +2262,77 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatM return (jlong) chatMessage; } +extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatMessage2(JNIEnv* env + ,jobject thiz + ,jlong ptr + ,jstring jmessage + ,jstring jurl + ,jint state + ,jlong time + ,jboolean read + ,jboolean incoming) { + const char* message = jmessage?env->GetStringUTFChars(jmessage, NULL):NULL; + const char* url = jurl?env->GetStringUTFChars(jurl, NULL):NULL; + + LinphoneChatMessage *chatMessage = linphone_chat_room_create_message_2( + (LinphoneChatRoom *)ptr, message, url, (LinphoneChatMessageState)state, + (time_t)time, read, incoming); + + if (jmessage != NULL) + env->ReleaseStringUTFChars(jmessage, message); + if (jurl != NULL) + env->ReleaseStringUTFChars(jurl, url); + + return (jlong) chatMessage; +} +extern "C" jint Java_org_linphone_core_LinphoneChatRoomImpl_getUnreadMessagesCount(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jint) linphone_chat_room_get_unread_messages_count((LinphoneChatRoom*)ptr); +} +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteHistory(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_room_delete_history((LinphoneChatRoom*)ptr); +} +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_deleteMessage(JNIEnv* env + ,jobject thiz + ,jlong room + ,jlong msg) { + linphone_chat_room_delete_message((LinphoneChatRoom*)room, (LinphoneChatMessage*)msg); +} +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_markAsRead(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_room_mark_as_read((LinphoneChatRoom*)ptr); +} + +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_updateUrl(JNIEnv* env + ,jobject thiz + ,jlong room + ,jlong msg) { + linphone_chat_room_update_url((LinphoneChatRoom*)room, (LinphoneChatMessage*)msg); +} + +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_destroy(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + 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) { + linphone_chat_message_store((LinphoneChatMessage*)ptr); +} + extern "C" jstring Java_org_linphone_core_LinphoneChatMessageImpl_getText(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -1886,6 +2391,48 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getTime(JNIEnv* return (jlong) linphone_chat_message_get_time((LinphoneChatMessage*)ptr); } +extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getStatus(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jint) linphone_chat_message_get_state((LinphoneChatMessage*)ptr); +} + +extern "C" jboolean Java_org_linphone_core_LinphoneChatMessageImpl_isRead(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jboolean) linphone_chat_message_is_read((LinphoneChatMessage*)ptr); +} + +extern "C" jboolean Java_org_linphone_core_LinphoneChatMessageImpl_isOutgoing(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jboolean) linphone_chat_message_is_outgoing((LinphoneChatMessage*)ptr); +} + +extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getStorageId(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jint) linphone_chat_message_get_storage_id((LinphoneChatMessage*)ptr); +} + +extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getChatRooms(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + MSList* chats = linphone_core_get_chat_rooms((LinphoneCore*)ptr); + int chatsSize = ms_list_size(chats); + jlongArray jChats = env->NewLongArray(chatsSize); + jlong *jInternalArray = env->GetLongArrayElements(jChats, NULL); + + for (int i = 0; i < chatsSize; i++) { + jInternalArray[i] = (unsigned long) (chats->data); + chats = chats->next; + } + + env->ReleaseLongArrayElements(jChats, jInternalArray, 0); + + return jChats; +} + extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage(JNIEnv* env ,jobject thiz ,jlong ptr @@ -1927,6 +2474,7 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* jobject listener = env->NewGlobalRef(jlistener); linphone_chat_room_send_message2((LinphoneChatRoom*)ptr, (LinphoneChatMessage*)jmessage, chat_room_impl_callback, (void*)listener); } + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env ,jobject thiz ,jlong lc @@ -1934,9 +2482,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* jobject oldWindow = (jobject) linphone_core_get_native_video_window_id((LinphoneCore*)lc); if (obj != NULL) { obj = env->NewGlobalRef(obj); - } + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): NewGlobalRef(%p)",obj); + }else ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): setting to NULL"); linphone_core_set_native_video_window_id((LinphoneCore*)lc,(unsigned long)obj); if (oldWindow != NULL) { + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): DeleteGlobalRef(%p)",oldWindow); env->DeleteGlobalRef(oldWindow); } } @@ -1948,9 +2498,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(JNIEn jobject oldWindow = (jobject) linphone_core_get_native_preview_window_id((LinphoneCore*)lc); if (obj != NULL) { obj = env->NewGlobalRef(obj); - } + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): NewGlobalRef(%p)",obj); + }else ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): setting to NULL"); linphone_core_set_native_preview_window_id((LinphoneCore*)lc,(unsigned long)obj); if (oldWindow != NULL) { + ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): DeleteGlobalRef(%p)",oldWindow); env->DeleteGlobalRef(oldWindow); } } @@ -2016,6 +2568,20 @@ extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setMediaEncryption linphone_call_params_set_media_encryption((LinphoneCallParams*)cp,(LinphoneMediaEncryption)jmenc); } +extern "C" jint Java_org_linphone_core_LinphoneCallParamsImpl_getPrivacy(JNIEnv* env + ,jobject thiz + ,jlong cp + ) { + return (jint)linphone_call_params_get_privacy((LinphoneCallParams*)cp); +} + +extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setPrivacy(JNIEnv* env + ,jobject thiz + ,jlong cp + ,jint privacy) { + linphone_call_params_set_privacy((LinphoneCallParams*)cp,privacy); +} + 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); } @@ -2109,6 +2675,12 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreferredVideoSize(JN linphone_core_set_preferred_video_size((LinphoneCore *)lc, vsize); } +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreImpl_setPreferredVideoSizeByName(JNIEnv *env, jobject thiz, jlong lc, jstring jName) { + const char* cName = env->GetStringUTFChars(jName, NULL); + linphone_core_set_preferred_video_size_by_name((LinphoneCore *)lc, cName); + env->ReleaseStringUTFChars(jName, cName); +} + extern "C" jintArray Java_org_linphone_core_LinphoneCoreImpl_getPreferredVideoSize(JNIEnv *env, jobject thiz, jlong lc){ MSVideoSize vsize = linphone_core_get_preferred_video_size((LinphoneCore *)lc); jintArray arr = env->NewIntArray(2); @@ -2129,10 +2701,18 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUseSipInfoForDtmfs(JN linphone_core_set_use_info_for_dtmf((LinphoneCore *)lc, (bool) use); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_getUseSipInfoForDtmfs(JNIEnv *env, jobject thiz, jlong lc){ + return linphone_core_get_use_info_for_dtmf((LinphoneCore *)lc); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUseRfc2833ForDtmfs(JNIEnv *env, jobject thiz, jlong lc, jboolean use){ linphone_core_set_use_rfc2833_for_dtmf((LinphoneCore *)lc, (bool) use); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_getUseRfc2833ForDtmfs(JNIEnv *env, jobject thiz, jlong lc){ + return (jboolean) linphone_core_get_use_rfc2833_for_dtmf((LinphoneCore *)lc); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDownloadPtime(JNIEnv *env, jobject thiz, jlong lc, jint ptime){ linphone_core_set_download_ptime((LinphoneCore *)lc, (int) ptime); } @@ -2144,8 +2724,21 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUploadPtime(JNIEnv *e extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getState(JNIEnv* env,jobject thiz,jlong ptr) { return (jint) linphone_proxy_config_get_state((const LinphoneProxyConfig *) ptr); } + extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setExpires(JNIEnv* env,jobject thiz,jlong ptr,jint delay) { - linphone_proxy_config_expires((LinphoneProxyConfig *) ptr, (int) delay); + linphone_proxy_config_set_expires((LinphoneProxyConfig *) ptr, (int) delay); +} + +extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getExpires(JNIEnv* env,jobject thiz,jlong ptr) { + return linphone_proxy_config_get_expires((LinphoneProxyConfig *) ptr); +} + +extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setPrivacy(JNIEnv* env,jobject thiz,jlong ptr,jint privacy) { + linphone_proxy_config_set_privacy((LinphoneProxyConfig *) ptr, (int) privacy); +} + +extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getPrivacy(JNIEnv* env,jobject thiz,jlong ptr) { + return linphone_proxy_config_get_privacy((LinphoneProxyConfig *) ptr); } extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getDuration(JNIEnv* env,jobject thiz,jlong ptr) { @@ -2190,6 +2783,10 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableIpv6(JNIEnv* env,j linphone_core_enable_ipv6((LinphoneCore*)lc,enable); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isIpv6Enabled(JNIEnv* env,jobject thiz, jlong lc) { + return (jboolean)linphone_core_ipv6_enabled((LinphoneCore*)lc); +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_adjustSoftwareVolume(JNIEnv* env,jobject thiz ,jlong ptr, jint db) { linphone_core_set_playback_gain_db((LinphoneCore *) ptr, db); @@ -2281,10 +2878,10 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setZrtpSecretsCache(JNIE extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_findCallFromUri(JNIEnv *env,jobject thiz,jlong pCore, jstring jUri) { const char* cUri=env->GetStringUTFChars(jUri, NULL); - LinphoneCall *call=linphone_core_find_call_from_uri((LinphoneCore *) pCore,cUri); + const LinphoneCall *call=linphone_core_find_call_from_uri((const LinphoneCore *) pCore,cUri); env->ReleaseStringUTFChars(jUri, cUri); LinphoneCoreData *lcdata=(LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)pCore); - return (jobject) lcdata->getCall(env,call); + return (jobject) lcdata->getCall(env,(LinphoneCall*)call); } @@ -2438,6 +3035,16 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoPolicy(JNIEnv *e linphone_core_set_video_policy((LinphoneCore *)lc, &vpol); } +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_getVideoAutoInitiatePolicy(JNIEnv *env, jobject thiz, jlong lc){ + const LinphoneVideoPolicy *vpol = linphone_core_get_video_policy((LinphoneCore *)lc); + return (jboolean) vpol->automatically_initiate; +} + +extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_getVideoAutoAcceptPolicy(JNIEnv *env, jobject thiz, jlong lc){ + const LinphoneVideoPolicy *vpol = linphone_core_get_video_policy((LinphoneCore *)lc); + return (jboolean) vpol->automatically_accept; +} + extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setStaticPicture(JNIEnv *env, jobject thiz, jlong lc, jstring path) { const char *cpath = env->GetStringUTFChars(path, NULL); linphone_core_set_static_picture((LinphoneCore *)lc, cpath); @@ -2510,6 +3117,80 @@ extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getUpnpExternalIpaddr return jvalue; } + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: subscribe + * 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){ + LinphoneCore *lc=(LinphoneCore*)coreptr; + LinphoneAddress *addr=(LinphoneAddress*)addrptr; + LinphoneContent content={0}; + LinphoneEvent *ev; + jobject jev=NULL; + const char *evname=env->GetStringUTFChars(jevname,NULL); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + + 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.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); + } + ev=linphone_core_subscribe(lc,addr,evname,expires,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); + } + env->ReleaseStringUTFChars(jevname,evname); + if (ev){ + jev=lcData->getEvent(env,ev); + } + return jev; +} + +/* + * Class: org_linphone_core_LinphoneCoreImpl + * Method: publish + * Signature: (JJLjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneCoreImpl_publish(JNIEnv *env, jobject jobj, jlong coreptr, jlong addrptr, jstring jevname, jint expires, + jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ + LinphoneCore *lc=(LinphoneCore*)coreptr; + LinphoneAddress *addr=(LinphoneAddress*)addrptr; + LinphoneContent content={0}; + LinphoneEvent *ev; + jobject jev=NULL; + const char *evname=env->GetStringUTFChars(jevname,NULL); + LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc); + + 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.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); + } + ev=linphone_core_publish(lc,addr,evname,expires,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); + } + env->ReleaseStringUTFChars(jevname,evname); + if (ev){ + jev=lcData->getEvent(env,ev); + } + return jev; +} + +// LpConfig extern "C" jlong Java_org_linphone_core_LpConfigImpl_newLpConfigImpl(JNIEnv *env, jobject thiz, jstring file) { const char *cfile = env->GetStringUTFChars(file, NULL); LpConfig *lp = lp_config_new(cfile); @@ -2536,3 +3217,1180 @@ extern "C" void Java_org_linphone_core_LpConfigImpl_setInt(JNIEnv *env, jobject env->ReleaseStringUTFChars(key, ckey); } +extern "C" jint Java_org_linphone_core_LpConfigImpl_getInt(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jint defaultValue) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + int returnValue = lp_config_get_int((LpConfig *)lpc, csection, ckey, (int) defaultValue); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + return (jint) returnValue; +} + +extern "C" void Java_org_linphone_core_LpConfigImpl_setFloat(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jfloat value) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + lp_config_set_float((LpConfig *)lpc, csection, ckey, (float) value); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); +} + +extern "C" jfloat Java_org_linphone_core_LpConfigImpl_getFloat(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jfloat defaultValue) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + float returnValue = lp_config_get_float((LpConfig *)lpc, csection, ckey, (float) defaultValue); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + return (jfloat) returnValue; +} + +extern "C" void Java_org_linphone_core_LpConfigImpl_setBool(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jboolean value) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + lp_config_set_int((LpConfig *)lpc, csection, ckey, value ? 1 : 0); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); +} + +extern "C" jboolean Java_org_linphone_core_LpConfigImpl_getBool(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jboolean defaultValue) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + int returnValue = lp_config_get_int((LpConfig *)lpc, csection, ckey, defaultValue ? 1 : 0); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + return (jboolean) returnValue == 1; +} + +extern "C" void Java_org_linphone_core_LpConfigImpl_setString(JNIEnv *env, jobject thiz, jlong lpc, + 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); + lp_config_set_string((LpConfig *)lpc, csection, ckey, cvalue); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + env->ReleaseStringUTFChars(value, cvalue); +} + +extern "C" jstring Java_org_linphone_core_LpConfigImpl_getString(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jstring defaultValue) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + const char *cvalue = defaultValue ? env->GetStringUTFChars(defaultValue, NULL) : NULL; + + const char *returnValue = lp_config_get_string((LpConfig *)lpc, csection, ckey, cvalue); + + jstring jreturnValue = NULL; + if (returnValue) + jreturnValue = env->NewStringUTF(returnValue); + + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + if (cvalue) + env->ReleaseStringUTFChars(defaultValue, cvalue); + + return jreturnValue; +} +extern "C" void Java_org_linphone_core_LpConfigImpl_setIntRange(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jint min, jint max) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + lp_config_set_range((LpConfig *)lpc, csection, ckey, min, max); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); +} + +extern "C" jintArray Java_org_linphone_core_LpConfigImpl_getIntRange(JNIEnv *env, jobject thiz, jlong lpc, + jstring section, jstring key, jint defaultmin, jint defaultmax) { + const char *csection = env->GetStringUTFChars(section, NULL); + const char *ckey = env->GetStringUTFChars(key, NULL); + int *values = (int*)calloc(2, sizeof(int)); + lp_config_get_range((LpConfig *)lpc, csection, ckey, &values[0], &values[1], defaultmin, defaultmax); + jintArray returnValues = env->NewIntArray(2); + env->SetIntArrayRegion(returnValues, 0, 2, values); + ms_free(values); + env->ReleaseStringUTFChars(section, csection); + env->ReleaseStringUTFChars(key, ckey); + return returnValues; +} + +static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *content){ + jclass contentClass; + jmethodID ctor; + jstring jtype, jsubtype, jencoding; + jbyteArray jdata=NULL; + + contentClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneContentImpl")); + ctor = env->GetMethodID(contentClass,"", "(Ljava/lang/String;Ljava/lang/String;[BLjava/lang/String;)V"); + + jtype=env->NewStringUTF(content->type); + jsubtype=env->NewStringUTF(content->subtype); + jencoding=content->encoding ? env->NewStringUTF(content->encoding) : NULL; + + if (content->data){ + jdata=env->NewByteArray(content->size); + env->SetByteArrayRegion(jdata,0,content->size,(jbyte*)content->data); + } + + jobject jobj=env->NewObject(contentClass,ctor,jtype, jsubtype, jdata,jencoding); + env->DeleteGlobalRef(contentClass); + return jobj; +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: getContent + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getContent(JNIEnv *env, jobject jobj, jlong infoptr){ + const LinphoneContent *content=linphone_info_message_get_content((LinphoneInfoMessage*)infoptr); + if (content){ + return create_java_linphone_content(env,content); + } + return NULL; +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: setContent + * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_setContent(JNIEnv *env, jobject jobj, jlong infoptr, jstring jtype, jstring jsubtype, jstring jdata){ + LinphoneContent content={0}; + + content.type=(char*)env->GetStringUTFChars(jtype,NULL); + content.subtype=(char*)env->GetStringUTFChars(jsubtype,NULL); + content.data=(void*)env->GetStringUTFChars(jdata,NULL); + content.size=strlen((char*)content.data); + linphone_info_message_set_content((LinphoneInfoMessage*)infoptr,&content); + env->ReleaseStringUTFChars(jtype,content.type); + env->ReleaseStringUTFChars(jsubtype,content.subtype); + env->ReleaseStringUTFChars(jdata,(char*)content.data); +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: addHeader + * Signature: (JLjava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_addHeader(JNIEnv *env, jobject jobj, jlong infoptr, jstring jname, jstring jvalue){ + const char *name=NULL,*value=NULL; + name=env->GetStringUTFChars(jname,NULL); + value=env->GetStringUTFChars(jvalue,NULL); + linphone_info_message_add_header((LinphoneInfoMessage*)infoptr,name,value); + env->ReleaseStringUTFChars(jname,name); + env->ReleaseStringUTFChars(jvalue,value); +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: getHeader + * Signature: (JLjava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_getHeader(JNIEnv *env, jobject jobj, jlong infoptr, jstring jname){ + const char *name=name=env->GetStringUTFChars(jname,NULL); + const char *ret=linphone_info_message_get_header((LinphoneInfoMessage*)infoptr,name); + env->ReleaseStringUTFChars(jname,name); + return ret ? env->NewStringUTF(ret) : NULL; +} + +/* + * Class: org_linphone_core_LinphoneInfoMessageImpl + * Method: delete + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneInfoMessageImpl_delete(JNIEnv *env, jobject jobj , jlong infoptr){ + linphone_info_message_destroy((LinphoneInfoMessage*)infoptr); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreFactoryImpl__1setLogHandler(JNIEnv *env, jobject jfactory, jobject jhandler){ + static int init_done=FALSE; + + if (!init_done){ + handler_class=(jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneLogHandler")); + loghandler_id=env->GetMethodID(handler_class,"log", "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)V"); + if (loghandler_id==NULL) ms_fatal("log method not found"); + init_done=TRUE; + } + if (handler_obj) { + env->DeleteGlobalRef(handler_obj); + handler_obj=NULL; + } + if (jhandler){ + handler_obj=env->NewGlobalRef(jhandler); + } +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: getEventName + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneEventImpl_getEventName(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + const char *evname=linphone_event_get_name(ev); + return evname ? env->NewStringUTF(evname) : NULL; +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: acceptSubscription + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_acceptSubscription(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return linphone_event_accept_subscription(ev); +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: denySubscription + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_denySubscription(JNIEnv *env, jobject jobj, jlong evptr, int reason){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return linphone_event_deny_subscription(ev,(LinphoneReason)reason); +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: notify + * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_notify(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ + LinphoneContent content={0}; + LinphoneEvent *ev=(LinphoneEvent*)evptr; + jint err; + + 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.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); + } + + err=linphone_event_notify(ev,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); + } + return err; +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: updateSubscribe + * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updateSubscribe(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ + LinphoneContent content={0}; + LinphoneEvent *ev=(LinphoneEvent*)evptr; + jint err; + + 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.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); + } + + err=linphone_event_update_subscribe(ev,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); + } + return err; +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: updatePublish + * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_updatePublish(JNIEnv *env, jobject jobj, jlong evptr, jstring jtype, jstring jsubtype, jbyteArray jdata, jstring jencoding){ + LinphoneContent content={0}; + LinphoneEvent *ev=(LinphoneEvent*)evptr; + jint err; + + 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.data=(void*)env->GetByteArrayElements(jdata,NULL); + content.size=env->GetArrayLength(jdata); + } + + err=linphone_event_update_publish(ev,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); + } + return err; +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: terminate + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_terminate(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + linphone_event_terminate(ev); + return 0; +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: getReason + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getReason(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return linphone_event_get_reason(ev); +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: getSubscriptionDir + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getSubscriptionDir(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return linphone_event_get_subscription_dir(ev); +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: getSubscriptionState + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneEventImpl_getSubscriptionState(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + return linphone_event_get_subscription_state(ev); +} + +/* + * Class: org_linphone_core_LinphoneEventImpl + * Method: unref + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneEventImpl_unref(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneEvent *ev=(LinphoneEvent*)evptr; + linphone_event_unref(ev); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: newPresenceModelImpl + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceModelImpl__(JNIEnv *env, jobject jobj) { + return (jlong)linphone_presence_model_new(); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: newPresenceModelImpl + * Signature: (ILjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceModelImpl__ILjava_lang_String_2(JNIEnv *env, jobject jobj, jint type, jstring description) { + LinphonePresenceModel *model; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + model = linphone_presence_model_new_with_activity((LinphonePresenceActivityType)type, cdescription); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); + return (jlong)model; +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: newPresenceModelImpl + * Signature: (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_newPresenceModelImpl__ILjava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2( + JNIEnv *env, jobject jobj, jint type, jstring description, jstring note, jstring lang) { + LinphonePresenceModel *model; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + 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); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); + if (cnote) env->ReleaseStringUTFChars(note, cnote); + if (clang) env->ReleaseStringUTFChars(lang, clang); + return (jlong)model; +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: unref + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PresenceModelImpl_unref(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + linphone_presence_model_unref(model); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getBasicStatus + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_getBasicStatus(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jint)linphone_presence_model_get_basic_status(model); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: setBasicStatus + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_setBasicStatus(JNIEnv *env, jobject jobj, jlong ptr, jint basic_status) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jint)linphone_presence_model_set_basic_status(model, (LinphonePresenceBasicStatus)basic_status); +} + + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getTimestamp + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_getTimestamp(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jlong)linphone_presence_model_get_timestamp(model); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getContact + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceModelImpl_getContact(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + char *ccontact = linphone_presence_model_get_contact(model); + jstring jcontact = ccontact ? env->NewStringUTF(ccontact) : NULL; + if (ccontact) ms_free(ccontact); + return jcontact; +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: setContact + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PresenceModelImpl_setContact(JNIEnv *env, jobject jobj, jlong ptr, jstring contact) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + const char *ccontact = contact ? env->GetStringUTFChars(contact, NULL) : NULL; + linphone_presence_model_set_contact(model, ccontact); + if (ccontact) env->ReleaseStringUTFChars(contact, ccontact); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getActivity + * Signature: (J)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresenceModelImpl_getActivity(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + LinphonePresenceActivity *activity = linphone_presence_model_get_activity(model); + if (activity == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceActivityImpl", linphone_presence_activity, activity) +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: setActivity + * Signature: (JILjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_setActivity(JNIEnv *env, jobject jobj, jlong ptr, jint acttype, jstring description) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + jint res = (jint)linphone_presence_model_set_activity(model, (LinphonePresenceActivityType)acttype, cdescription); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); + return res; +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getNbActivities + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_getNbActivities(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jlong)linphone_presence_model_get_nb_activities(model); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getNthActivity + * Signature: (JJ)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresenceModelImpl_getNthActivity(JNIEnv *env, jobject jobj, jlong ptr, jlong idx) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + LinphonePresenceActivity *activity = linphone_presence_model_get_nth_activity(model, (unsigned int)idx); + if (activity == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceActivityImpl", linphone_presence_activity, activity) +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: addActivity + * Signature: (JILjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_addActivity(JNIEnv *env, jobject jobj, jlong ptr, jlong activityPtr) { + return (jint)linphone_presence_model_add_activity((LinphonePresenceModel *)ptr, (LinphonePresenceActivity *)activityPtr); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: clearActivities + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_clearActivities(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jint)linphone_presence_model_clear_activities(model); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getNote + * Signature: (JLjava/lang/String;)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresenceModelImpl_getNote(JNIEnv *env , jobject jobj, jlong ptr, jstring lang) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL; + LinphonePresenceNote *note = linphone_presence_model_get_note(model, clang); + if (clang) env->ReleaseStringUTFChars(lang, clang); + if (note == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceNoteImpl", linphone_presence_note, note) +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: addNote + * Signature: (JLjava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_addNote(JNIEnv *env, jobject jobj, jlong ptr, jstring description, jstring lang) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL; + jint res = (jint)linphone_presence_model_add_note(model, cdescription, clang); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); + if (clang) env->ReleaseStringUTFChars(lang, clang); + return res; +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: clearNotes + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_clearNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jint)linphone_presence_model_clear_notes(model); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getNbServices + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_getNbServices(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jlong)linphone_presence_model_get_nb_services(model); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getNthService + * Signature: (JJ)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresenceModelImpl_getNthService(JNIEnv *env, jobject jobj, jlong ptr, jlong idx) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + LinphonePresenceService *service = linphone_presence_model_get_nth_service(model, (unsigned int)idx); + if (service == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceServiceImpl", linphone_presence_service, service) +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: addService + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_addService(JNIEnv *env, jobject jobj, jlong ptr, jlong servicePtr) { + return (jint)linphone_presence_model_add_service((LinphonePresenceModel *)ptr, (LinphonePresenceService *)servicePtr); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: clearServices + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_clearServices(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jint)linphone_presence_model_clear_services(model); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getNbPersons + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceModelImpl_getNbPersons(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jlong)linphone_presence_model_get_nb_persons(model); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: getNthPerson + * Signature: (JJ)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresenceModelImpl_getNthPerson(JNIEnv *env, jobject jobj, jlong ptr, jlong idx) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + LinphonePresencePerson *person = linphone_presence_model_get_nth_person(model, (unsigned int)idx); + if (person == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresencePersonImpl", linphone_presence_person, person) +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: addPerson + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_addPerson(JNIEnv *env, jobject jobj, jlong ptr, jlong personPtr) { + return (jint)linphone_presence_model_add_person((LinphonePresenceModel *)ptr, (LinphonePresencePerson *)personPtr); +} + +/* + * Class: org_linphone_core_PresenceModelImpl + * Method: clearPersons + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceModelImpl_clearPersons(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceModel *model = (LinphonePresenceModel *)ptr; + return (jint)linphone_presence_model_clear_persons(model); +} + +/* + * Class: org_linphone_core_PresenceActivityImpl + * Method: newPresenceActivityImpl + * Signature: (ILjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceActivityImpl_newPresenceActivityImpl(JNIEnv *env, jobject jobj, jint type, jstring description) { + LinphonePresenceActivity *activity; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + activity = linphone_presence_activity_new((LinphonePresenceActivityType)type, cdescription); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); + return (jlong)activity; +} + + /* + * Class: org_linphone_core_PresenceActivityImpl + * Method: unref + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PresenceActivityImpl_unref(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceActivity *activity = (LinphonePresenceActivity *)ptr; + linphone_presence_activity_unref(activity); +} + + /* + * Class: org_linphone_core_PresenceActivityImpl + * Method: toString + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceActivityImpl_toString(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceActivity *activity = (LinphonePresenceActivity *)ptr; + char *cactstr = linphone_presence_activity_to_string(activity); + jstring jactstr = cactstr ? env->NewStringUTF(cactstr) : NULL; + if (cactstr) ms_free(cactstr); + return jactstr; +} + +/* + * Class: org_linphone_core_PresenceActivityImpl + * Method: getType + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceActivityImpl_getType(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceActivity *activity = (LinphonePresenceActivity *)ptr; + return (jint)linphone_presence_activity_get_type(activity); +} + +/* + * Class: org_linphone_core_PresenceActivityImpl + * Method: setType + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceActivityImpl_setType(JNIEnv *env, jobject jobj, jlong ptr, jint type) { + LinphonePresenceActivity *activity = (LinphonePresenceActivity *)ptr; + return (jint)linphone_presence_activity_set_type(activity, (LinphonePresenceActivityType)type); +} + +/* + * Class: org_linphone_core_PresenceActivityImpl + * Method: getDescription + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceActivityImpl_getDescription(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceActivity *activity = (LinphonePresenceActivity *)ptr; + const char *cdescription = linphone_presence_activity_get_description(activity); + return cdescription ? env->NewStringUTF(cdescription) : NULL; +} + +/* + * Class: org_linphone_core_PresenceActivityImpl + * Method: setDescription + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceActivityImpl_setDescription(JNIEnv *env, jobject jobj, jlong ptr, jstring description) { + LinphonePresenceActivity *activity = (LinphonePresenceActivity *)ptr; + const char *cdescription = description ? env->GetStringUTFChars(description, NULL) : NULL; + linphone_presence_activity_set_description(activity, cdescription); + if (cdescription) env->ReleaseStringUTFChars(description, cdescription); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: newPresenceServiceImpl + * Signature: (Ljava/lang/String;ILjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_newPresenceServiceImpl(JNIEnv *env, jobject jobj, jstring id, jint basic_status, jstring contact) { + LinphonePresenceService *service; + 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); + if (cid) env->ReleaseStringUTFChars(id, cid); + if (ccontact) env->ReleaseStringUTFChars(contact, ccontact); + return (jlong)service; +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: unref + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PresenceServiceImpl_unref(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + linphone_presence_service_unref(service); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: getId + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceServiceImpl_getId(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + char *cid = linphone_presence_service_get_id(service); + jstring jid = cid ? env->NewStringUTF(cid) : NULL; + if (cid) ms_free(cid); + return jid; +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: setId + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_setId(JNIEnv *env, jobject jobj, jlong ptr, jstring id) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL; + linphone_presence_service_set_id(service, cid); + if (cid) env->ReleaseStringUTFChars(id, cid); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: getBasicStatus + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_getBasicStatus(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + return (jint)linphone_presence_service_get_basic_status(service); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: setBasicStatus + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_setBasicStatus(JNIEnv *env, jobject jobj, jlong ptr, jint basic_status) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + return (jint)linphone_presence_service_set_basic_status(service, (LinphonePresenceBasicStatus)basic_status); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: getContact + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceServiceImpl_getContact(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + char *ccontact = linphone_presence_service_get_contact(service); + jstring jcontact = ccontact ? env->NewStringUTF(ccontact) : NULL; + if (ccontact) ms_free(ccontact); + return jcontact; +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: setContact + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_setContact(JNIEnv *env, jobject jobj, jlong ptr, jstring contact) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + const char *ccontact = contact ? env->GetStringUTFChars(contact, NULL) : NULL; + linphone_presence_service_set_contact(service, ccontact); + if (ccontact) env->ReleaseStringUTFChars(contact, ccontact); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: getNbNotes + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceServiceImpl_getNbNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + return (jlong)linphone_presence_service_get_nb_notes(service); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: getNthNote + * Signature: (JJ)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresenceServiceImpl_getNthNote(JNIEnv *env, jobject jobj, jlong ptr, jlong idx) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + LinphonePresenceNote *note = linphone_presence_service_get_nth_note(service, (unsigned int)idx); + if (note == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceNoteImpl", linphone_presence_note, note) +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: addNote + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_addNote(JNIEnv *env, jobject jobj, jlong ptr, jlong notePtr) { + return (jint)linphone_presence_service_add_note((LinphonePresenceService *)ptr, (LinphonePresenceNote *)notePtr); +} + +/* + * Class: org_linphone_core_PresenceServiceImpl + * Method: clearNotes + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceServiceImpl_clearNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceService *service = (LinphonePresenceService *)ptr; + return (jint)linphone_presence_service_clear_notes(service); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: newPresencePersonImpl + * Signature: (Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_newPresencePersonImpl(JNIEnv *env, jobject jobj, jstring id) { + LinphonePresencePerson *person; + const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL; + person = linphone_presence_person_new(cid); + if (cid) env->ReleaseStringUTFChars(id, cid); + return (jlong)person; +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: unref + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PresencePersonImpl_unref(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + linphone_presence_person_unref(person); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: getId + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PresencePersonImpl_getId(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + char *cid = linphone_presence_person_get_id(person); + jstring jid = cid ? env->NewStringUTF(cid) : NULL; + if (cid) ms_free(cid); + return jid; +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: setId + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_setId(JNIEnv *env, jobject jobj, jlong ptr, jstring id) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + const char *cid = id ? env->GetStringUTFChars(id, NULL) : NULL; + linphone_presence_person_set_id(person, cid); + if (cid) env->ReleaseStringUTFChars(id, cid); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: getNbActivities + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_getNbActivities(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + return (jlong)linphone_presence_person_get_nb_activities(person); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: getNthActivity + * Signature: (JJ)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresencePersonImpl_getNthActivity(JNIEnv *env, jobject jobj, jlong ptr, jlong idx) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + LinphonePresenceActivity *activity = linphone_presence_person_get_nth_activity(person, (unsigned int)idx); + if (activity == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceActivityImpl", linphone_presence_activity, activity) +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: addActivity + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_addActivity(JNIEnv *env, jobject jobj, jlong ptr, jlong activityPtr) { + return (jint)linphone_presence_person_add_activity((LinphonePresencePerson *)ptr, (LinphonePresenceActivity *)activityPtr); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: clearActivities + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_clearActivities(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + return (jint)linphone_presence_person_clear_activities(person); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: getNbNotes + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_getNbNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + return (jlong)linphone_presence_person_get_nb_notes(person); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: getNthNote + * Signature: (JJ)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresencePersonImpl_getNthNote(JNIEnv *env, jobject jobj, jlong ptr, jlong idx) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + LinphonePresenceNote *note = linphone_presence_person_get_nth_note(person, (unsigned int)idx); + if (note == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceNoteImpl", linphone_presence_note, note) +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: addNote + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_addNote(JNIEnv *env, jobject jobj, jlong ptr, jlong notePtr) { + return (jint)linphone_presence_person_add_note((LinphonePresencePerson *)ptr, (LinphonePresenceNote *)notePtr); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: clearNotes + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_clearNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + return (jint)linphone_presence_person_clear_notes(person); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: getNbActivitiesNotes + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresencePersonImpl_getNbActivitiesNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + return (jlong)linphone_presence_person_get_nb_activities_notes(person); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: getNthActivitiesNote + * Signature: (JJ)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_org_linphone_core_PresencePersonImpl_getNthActivitiesNote(JNIEnv *env, jobject jobj, jlong ptr, jlong idx) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + LinphonePresenceNote *note = linphone_presence_person_get_nth_activities_note(person, (unsigned int)idx); + if (note == NULL) return NULL; + RETURN_USER_DATA_OBJECT("PresenceNoteImpl", linphone_presence_note, note) +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: addActivitiesNote + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_addActivitiesNote(JNIEnv *env, jobject jobj, jlong ptr, jlong notePtr) { + return (jint)linphone_presence_person_add_activities_note((LinphonePresencePerson *)ptr, (LinphonePresenceNote *)notePtr); +} + +/* + * Class: org_linphone_core_PresencePersonImpl + * Method: clearActivitesNotes + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresencePersonImpl_clearActivitesNotes(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresencePerson *person = (LinphonePresencePerson *)ptr; + return (jint)linphone_presence_person_clear_activities_notes(person); +} + +/* + * Class: org_linphone_core_PresenceNoteImpl + * Method: newPresenceNoteImpl + * Signature: (Ljava/lang/String;Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_linphone_core_PresenceNoteImpl_newPresenceNoteImpl(JNIEnv *env, jobject jobj, jstring content, jstring lang) { + LinphonePresenceNote *note; + 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); + if (clang) env->ReleaseStringUTFChars(lang, clang); + if (ccontent) env->ReleaseStringUTFChars(content, ccontent); + return (jlong)note; +} + +/* + * Class: org_linphone_core_PresenceNoteImpl + * Method: unref + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PresenceNoteImpl_unref(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceNote *note = (LinphonePresenceNote *)ptr; + linphone_presence_note_unref(note); +} + +/* + * Class: org_linphone_core_PresenceNoteImpl + * Method: getContent + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceNoteImpl_getContent(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceNote *note = (LinphonePresenceNote *)ptr; + const char *ccontent = linphone_presence_note_get_content(note); + return ccontent ? env->NewStringUTF(ccontent) : NULL; +} + +/* + * Class: org_linphone_core_PresenceNoteImpl + * Method: setContent + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceNoteImpl_setContent(JNIEnv *env, jobject jobj, jlong ptr, jstring content) { + LinphonePresenceNote *note = (LinphonePresenceNote *)ptr; + const char *ccontent = content ? env->GetStringUTFChars(content, NULL) : NULL; + linphone_presence_note_set_content(note, ccontent); + if (ccontent) env->ReleaseStringUTFChars(content, ccontent); +} + +/* + * Class: org_linphone_core_PresenceNoteImpl + * Method: getLang + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PresenceNoteImpl_getLang(JNIEnv *env, jobject jobj, jlong ptr) { + LinphonePresenceNote *note = (LinphonePresenceNote *)ptr; + const char *clang = linphone_presence_note_get_lang(note); + return clang ? env->NewStringUTF(clang) : NULL; +} + +/* + * Class: org_linphone_core_PresenceNoteImpl + * Method: setLang + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_org_linphone_core_PresenceNoteImpl_setLang(JNIEnv *env, jobject jobj, jlong ptr, jstring lang) { + LinphonePresenceNote *note = (LinphonePresenceNote *)ptr; + const char *clang = lang ? env->GetStringUTFChars(lang, NULL) : NULL; + linphone_presence_note_set_lang(note, clang); + if (clang) env->ReleaseStringUTFChars(lang, clang); +} + +/* + * Class: org_linphone_core_PayloadTypeImpl + * Method: setRecvFmtp + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PayloadTypeImpl_setRecvFmtp(JNIEnv *env, jobject jobj, jlong ptr, jstring jfmtp){ + PayloadType *pt=(PayloadType *)ptr; + const char *fmtp=jfmtp ? env->GetStringUTFChars(jfmtp,NULL) : NULL; + payload_type_set_recv_fmtp(pt,fmtp); + if (fmtp) env->ReleaseStringUTFChars(jfmtp,fmtp); +} + +/* + * Class: org_linphone_core_PayloadTypeImpl + * Method: getRecvFmtp + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PayloadTypeImpl_getRecvFmtp(JNIEnv *env, jobject jobj, jlong ptr){ + PayloadType *pt=(PayloadType *)ptr; + const char *fmtp=pt->recv_fmtp; + return fmtp ? env->NewStringUTF(fmtp) : NULL; +} + +/* + * Class: org_linphone_core_PayloadTypeImpl + * Method: setSendFmtp + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_org_linphone_core_PayloadTypeImpl_setSendFmtp(JNIEnv *env, jobject jobj, jlong ptr , jstring jfmtp){ + PayloadType *pt=(PayloadType *)ptr; + const char *fmtp=jfmtp ? env->GetStringUTFChars(jfmtp,NULL) : NULL; + payload_type_set_send_fmtp(pt,fmtp); + if (fmtp) env->ReleaseStringUTFChars(jfmtp,fmtp); +} + +/* + * Class: org_linphone_core_PayloadTypeImpl + * Method: getSendFmtp + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_linphone_core_PayloadTypeImpl_getSendFmtp(JNIEnv *env, jobject jobj, jlong ptr){ + PayloadType *pt=(PayloadType *)ptr; + const char *fmtp=pt->send_fmtp; + return fmtp ? env->NewStringUTF(fmtp) : NULL; +} + + + + + diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index b80992ad1..04069e504 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -71,7 +71,7 @@ typedef void (*LinphoneEcCalibrationAudioUninit)(void *data); * * Start an echo calibration of the sound devices, in order to find adequate settings for the echo canceller automatically. **/ -int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, +LINPHONE_PUBLIC int linphone_core_start_echo_calibration(LinphoneCore *lc, LinphoneEcCalibrationCallback cb, LinphoneEcCalibrationAudioInit audio_init_cb, LinphoneEcCalibrationAudioUninit audio_uninit_cb, void *cb_data); /** * @ingroup IOS @@ -96,14 +96,14 @@ void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook *@param iso country code alpha2 *@return call country code or -1 if not found */ -int linphone_dial_plan_lookup_ccc_from_iso(const char* iso); +LINPHONE_PUBLIC int linphone_dial_plan_lookup_ccc_from_iso(const char* iso); /** * @ingroup misc *Function to get call country code from an e164 number, ex: +33952650121 will return 33 *@param e164 phone number *@return call country code or -1 if not found */ -int linphone_dial_plan_lookup_ccc_from_e164(const char* e164); +LINPHONE_PUBLIC int linphone_dial_plan_lookup_ccc_from_e164(const char* e164); #ifdef __cplusplus } diff --git a/coreapi/linphonefriend.h b/coreapi/linphonefriend.h index 6eb2ab2a2..66fbcea8e 100644 --- a/coreapi/linphonefriend.h +++ b/coreapi/linphonefriend.h @@ -19,22 +19,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef LINPHONEFRIEND_H_ #define LINPHONEFRIEND_H_ + +#include "linphonepresence.h" + #ifdef __cplusplus extern "C" { #endif + /** * @addtogroup buddy_list * @{ */ /** - * @ingroup buddy_list * Enum controlling behavior for incoming subscription request. *
Use by linphone_friend_set_inc_subscribe_policy() */ -typedef enum { +typedef enum _LinphoneSubscribePolicy { /** * Does not automatically accept an incoming subscription request. - * This policy implies that a decision has to be taken for each incoming subscription request notified by callback LinphoneCoreVTable.new_subscription_request + * This policy implies that a decision has to be taken for each incoming subscription request notified by callback LinphoneCoreVTable.new_subscription_requested * */ LinphoneSPWait, @@ -46,10 +49,11 @@ typedef enum { * Automatically accepts a subscription request. */ LinphoneSPAccept -}LinphoneSubscribePolicy; +} LinphoneSubscribePolicy; /** * Enum describing remote friend status + * @deprecated Use #LinphonePresenceModel and #LinphonePresenceActivity instead */ typedef enum _LinphoneOnlineStatus{ /** @@ -96,6 +100,10 @@ typedef enum _LinphoneOnlineStatus{ * Pending */ LinphoneStatusPending, + /** + * Vacation + */ + LinphoneStatusVacation, LinphoneStatusEnd }LinphoneOnlineStatus; @@ -111,47 +119,68 @@ typedef struct _LinphoneFriend LinphoneFriend; * Contructor * @return a new empty #LinphoneFriend */ -LinphoneFriend * linphone_friend_new(); +LINPHONE_PUBLIC LinphoneFriend * linphone_friend_new(); + /** - * Contructor same as linphone_friend_new() + linphone_friend_set_addr() + * Contructor same as linphone_friend_new() + linphone_friend_set_address() * @param addr a buddy address, must be a sip uri like sip:joe@sip.linphone.org * @return a new #LinphoneFriend with \link linphone_friend_get_address() address initialized \endlink */ -LinphoneFriend *linphone_friend_new_with_addr(const char *addr); +LINPHONE_PUBLIC LinphoneFriend *linphone_friend_new_with_address(const char *addr); + +/** + * Contructor same as linphone_friend_new() + linphone_friend_set_address() + * @deprecated Use #linphone_friend_new_with_address instead + */ +#define linphone_friend_new_with_addr linphone_friend_new_with_address /** * Destructor * @param lf #LinphoneFriend object */ -void linphone_friend_destroy(LinphoneFriend *lf); +LINPHONE_PUBLIC void linphone_friend_destroy(LinphoneFriend *lf); /** - * set #LinphoneAddress for this friend + * Set #LinphoneAddress for this friend * @param fr #LinphoneFriend object * @param address #LinphoneAddress */ -int linphone_friend_set_addr(LinphoneFriend *fr, const LinphoneAddress* address); +LINPHONE_PUBLIC int linphone_friend_set_address(LinphoneFriend *fr, const LinphoneAddress* address); /** - * set the display name for this friend - * @param lf #LinphoneFriend object - * @param name + * Set #LinphoneAddress for this friend + * @deprecated Use #linphone_friend_set_address instead */ -int linphone_friend_set_name(LinphoneFriend *lf, const char *name); +#define linphone_friend_set_addr linphone_friend_set_address /** - * get address of this friend + * Get address of this friend * @param lf #LinphoneFriend object * @return #LinphoneAddress */ -const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf); +LINPHONE_PUBLIC const LinphoneAddress *linphone_friend_get_address(const LinphoneFriend *lf); + +/** + * Set the display name for this friend + * @param lf #LinphoneFriend object + * @param name + */ +LINPHONE_PUBLIC int linphone_friend_set_name(LinphoneFriend *lf, const char *name); + +/** + * Get the display name for this friend + * @param lf #LinphoneFriend object + * @return The display name of this friend + */ +LINPHONE_PUBLIC const char * linphone_friend_get_name(const LinphoneFriend *lf); + /** * get subscription flag value * @param lf #LinphoneFriend object * @return returns true is subscription is activated for this friend * */ -bool_t linphone_friend_subscribes_enabled(const LinphoneFriend *lf); +LINPHONE_PUBLIC bool_t linphone_friend_subscribes_enabled(const LinphoneFriend *lf); #define linphone_friend_get_send_subscribe linphone_friend_subscribes_enabled /** @@ -160,108 +189,208 @@ bool_t linphone_friend_subscribes_enabled(const LinphoneFriend *lf); * @param val if TRUE this friend will receive subscription message */ -int linphone_friend_enable_subscribes(LinphoneFriend *fr, bool_t val); - +LINPHONE_PUBLIC int linphone_friend_enable_subscribes(LinphoneFriend *fr, bool_t val); #define linphone_friend_send_subscribe linphone_friend_enable_subscribes + /** * Configure incoming subscription policy for this friend. * @param fr #LinphoneFriend object * @param pol #LinphoneSubscribePolicy policy to apply. */ -int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol); +LINPHONE_PUBLIC int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscribePolicy pol); + /** * get current subscription policy for this #LinphoneFriend * @param lf #LinphoneFriend object * @return #LinphoneSubscribePolicy * */ -LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf); +LINPHONE_PUBLIC LinphoneSubscribePolicy linphone_friend_get_inc_subscribe_policy(const LinphoneFriend *lf); /** * Starts editing a friend configuration. * * Because friend configuration must be consistent, applications MUST * call linphone_friend_edit() before doing any attempts to modify - * friend configuration (such as \link linphone_friend_set_addr() address \endlink or \link linphone_friend_set_inc_subscribe_policy() subscription policy\endlink and so on). + * friend configuration (such as \link linphone_friend_set_address() address \endlink or \link linphone_friend_set_inc_subscribe_policy() subscription policy\endlink and so on). * Once the modifications are done, then the application must call * linphone_friend_done() to commit the changes. **/ -void linphone_friend_edit(LinphoneFriend *fr); +LINPHONE_PUBLIC void linphone_friend_edit(LinphoneFriend *fr); + /** * Commits modification made to the friend configuration. * @param fr #LinphoneFriend object **/ -void linphone_friend_done(LinphoneFriend *fr); - - - +LINPHONE_PUBLIC void linphone_friend_done(LinphoneFriend *fr); /** - * get friend status + * Get the status of a friend + * @param[in] lf A #LinphoneFriend object * @return #LinphoneOnlineStatus + * @deprecated Use linphone_friend_get_presence_model() instead */ -LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); -BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf); -void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key); -const char *linphone_friend_get_ref_key(const LinphoneFriend *lf); -bool_t linphone_friend_in_list(const LinphoneFriend *lf); - -#define linphone_friend_url(lf) ((lf)->url) +LINPHONE_PUBLIC LinphoneOnlineStatus linphone_friend_get_status(const LinphoneFriend *lf); /** - * return humain readable presence status - * @param ss + * Get the presence model of a friend + * @param[in] lf A #LinphoneFriend object + * @return A #LinphonePresenceModel object, or NULL if the friend do not have presence information (in which case he is considered offline) */ -const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); +LINPHONE_PUBLIC const LinphonePresenceModel * linphone_friend_get_presence_model(LinphoneFriend *lf); +/** + * Store user pointer to friend object. +**/ +LINPHONE_PUBLIC void linphone_friend_set_user_data(LinphoneFriend *lf, void *data); + +/** + * Retrieve user data associated with friend. +**/ +LINPHONE_PUBLIC void* linphone_friend_get_user_data(const LinphoneFriend *lf); + +LINPHONE_PUBLIC BuddyInfo * linphone_friend_get_info(const LinphoneFriend *lf); + +/** + * Set the reference key of a friend. + * @param[in] lf #LinphoneFriend object. + * @param[in] key The reference key to use for the friend. +**/ +LINPHONE_PUBLIC void linphone_friend_set_ref_key(LinphoneFriend *lf, const char *key); + +/** + * Get the reference key of a friend. + * @param[in] lf #LinphoneFriend object. + * @returns The reference key of the friend. +**/ +LINPHONE_PUBLIC const char *linphone_friend_get_ref_key(const LinphoneFriend *lf); + +/** + * Check that the given friend is in a friend list. + * @param[in] lf #LinphoneFriend object. + * @returns TRUE if the friend is in a friend list, FALSE otherwise. +**/ +LINPHONE_PUBLIC bool_t linphone_friend_in_list(const LinphoneFriend *lf); + + +/** + * Return humain readable presence status + * @param ss + * @deprecated Use #LinphonePresenceModel, #LinphonePresenceActivity and linphone_presence_activity_to_string() instead. + */ +LINPHONE_PUBLIC const char *linphone_online_status_to_string(LinphoneOnlineStatus ss); + + +/** + * Create a default LinphoneFriend. + * @param[in] lc #LinphoneCore object + * @return The created #LinphoneFriend object + */ +LINPHONE_PUBLIC LinphoneFriend * linphone_core_create_friend(LinphoneCore *lc); + +/** + * Create a LinphoneFriend from the given address. + * @param[in] lc #LinphoneCore object + * @param[in] address A string containing the address to create the LinphoneFriend from + * @return The created #LinphoneFriend object + */ +LINPHONE_PUBLIC LinphoneFriend * linphone_core_create_friend_with_address(LinphoneCore *lc, const char *address); /** * Set my presence status - * @param lc #LinphoneCore object - * @param minutes_away how long in away - * @param alternative_contact sip uri used to redirect call in state #LinphoneStatusMoved - * @param os #LinphoneOnlineStatus + * @param[in] lc #LinphoneCore object + * @param[in] minutes_away how long in away + * @param[in] alternative_contact sip uri used to redirect call in state #LinphoneStatusMoved + * @param[in] os #LinphoneOnlineStatus + * @deprecated Use linphone_core_set_presence_model() instead */ -void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *alternative_contact,LinphoneOnlineStatus os); -/** - * get my presence status - * @param lc #LinphoneCore object - * @return #LinphoneOnlineStatus - */ -LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc); +LINPHONE_PUBLIC void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *alternative_contact,LinphoneOnlineStatus os); + +/** + * Set my presence model + * @param[in] lc #LinphoneCore object + * @param[in] presence #LinphonePresenceModel + */ +LINPHONE_PUBLIC void linphone_core_set_presence_model(LinphoneCore *lc, LinphonePresenceModel *presence); + +/** + * Get my presence status + * @param[in] lc #LinphoneCore object + * @return #LinphoneOnlineStatus + * @deprecated Use linphone_core_get_presence_model() instead + */ +LINPHONE_PUBLIC LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc); + +/** + * Get my presence model + * @param[in] lc #LinphoneCore object + * @return A #LinphonePresenceModel object, or NULL if no presence model has been set. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_core_get_presence_model(const LinphoneCore *lc); + +/** + * @deprecated Use linphone_core_interpret_url() instead + */ +LINPHONE_PUBLIC void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result); -void linphone_core_interpret_friend_uri(LinphoneCore *lc, const char *uri, char **result); /** * Add a friend to the current buddy list, if \link linphone_friend_enable_subscribes() subscription attribute \endlink is set, a SIP SUBSCRIBE message is sent. * @param lc #LinphoneCore object * @param fr #LinphoneFriend to add */ -void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *fr); +LINPHONE_PUBLIC void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *fr); + /** * remove a friend from the buddy list * @param lc #LinphoneCore object * @param fr #LinphoneFriend to add */ -void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *fr); +LINPHONE_PUBLIC void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend *fr); + /** * Black list a friend. same as linphone_friend_set_inc_subscribe_policy() with #LinphoneSPDeny policy; * @param lc #LinphoneCore object * @param lf #LinphoneFriend to add */ -void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf); +LINPHONE_PUBLIC void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf); + /** - * get Buddy list of LinphoneFriend + * Get Buddy list of LinphoneFriend * @param lc #LinphoneCore object - * */ -const MSList * linphone_core_get_friend_list(const LinphoneCore *lc); + */ +LINPHONE_PUBLIC const MSList * linphone_core_get_friend_list(const LinphoneCore *lc); + /** - * notify all friends that have subscribed + * Notify all friends that have subscribed * @param lc #LinphoneCore object - * @param os #LinphoneOnlineStatus to notify - * */ -void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os); -LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr); -LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key); + * @param presence #LinphonePresenceModel to notify + */ +LINPHONE_PUBLIC void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence); + +/** + * Search a LinphoneFriend by its address. + * @param[in] lc #LinphoneCore object. + * @param[in] addr The address to use to search the friend. + * @returns The #LinphoneFriend object corresponding to the given address. + * @deprecated use linphone_core_find_friend() instead. + */ +LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_address(const LinphoneCore *lc, const char *addr); + +/** + * Search a LinphoneFriend by its address. + * @param[in] lc #LinphoneCore object. + * @param[in] addr The address to use to search the friend. + * @returns The #LinphoneFriend object corresponding to the given address. + */ +LINPHONE_PUBLIC LinphoneFriend *linphone_core_find_friend(const LinphoneCore *lc, const LinphoneAddress *addr); + +/** + * Search a LinphoneFriend by its reference key. + * @param[in] lc #LinphoneCore object. + * @param[in] key The reference key to use to search the friend. + * @returns The #LinphoneFriend object corresponding to the given reference key. + */ +LINPHONE_PUBLIC LinphoneFriend *linphone_core_get_friend_by_ref_key(const LinphoneCore *lc, const char *key); /** * @} diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h new file mode 100644 index 000000000..dd2045262 --- /dev/null +++ b/coreapi/linphonepresence.h @@ -0,0 +1,946 @@ +/* +linphonepresence.h +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. +*/ + +#ifndef LINPHONEPRESENCE_H_ +#define LINPHONEPRESENCE_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @addtogroup buddy_list + * @{ + */ + + +/** Basic status as defined in section 4.1.4 of RFC 3863 */ +typedef enum LinphonePresenceBasicStatus { + /** This value means that the associated contact element, if any, is ready to accept communication. */ + LinphonePresenceBasicStatusOpen, + + /** This value means that the associated contact element, if any, is unable to accept communication. */ + LinphonePresenceBasicStatusClosed +} LinphonePresenceBasicStatus; + +/** Activities as defined in section 3.2 of RFC 4480 */ +typedef enum LinphonePresenceActivityType { + /** This value is not defined in the RFC, it corresponds to no activity with a basic status of "closed". */ + LinphonePresenceActivityOffline, + + /** This value is not defined in the RFC, it corresponds to no activity with a basic status of "open". */ + LinphonePresenceActivityOnline, + + /** The person has a calendar appointment, without specifying exactly of what type. This activity is + * indicated if more detailed information is not available or the person chooses not to reveal more + * information. */ + LinphonePresenceActivityAppointment, + + /** The person is physically away from all interactive communication devices. */ + LinphonePresenceActivityAway, + + /** The person is eating the first meal of the day, usually eaten in the morning. */ + LinphonePresenceActivityBreakfast, + + /** The person is busy, without further details. */ + LinphonePresenceActivityBusy, + + /** The person is having his or her main meal of the day, eaten in the evening or at midday. */ + LinphonePresenceActivityDinner, + + /** This is a scheduled national or local holiday. */ + LinphonePresenceActivityHoliday, + + /** The person is riding in a vehicle, such as a car, but not steering. */ + LinphonePresenceActivityInTransit, + + /** The person is looking for (paid) work. */ + LinphonePresenceActivityLookingForWork, + + /** The person is eating his or her midday meal. */ + LinphonePresenceActivityLunch, + + /** The person is scheduled for a meal, without specifying whether it is breakfast, lunch, or dinner, + * or some other meal. */ + LinphonePresenceActivityMeal, + + /** The person is in an assembly or gathering of people, as for a business, social, or religious purpose. + * A meeting is a sub-class of an appointment. */ + LinphonePresenceActivityMeeting, + + /** The person is talking on the telephone. */ + LinphonePresenceActivityOnThePhone, + + /** The person is engaged in an activity with no defined representation. A string describing the activity + * in plain text SHOULD be provided. */ + LinphonePresenceActivityOther, + + /** A performance is a sub-class of an appointment and includes musical, theatrical, and cinematic + * performances as well as lectures. It is distinguished from a meeting by the fact that the person + * may either be lecturing or be in the audience, with a potentially large number of other people, + * making interruptions particularly noticeable. */ + LinphonePresenceActivityPerformance, + + /** The person will not return for the foreseeable future, e.g., because it is no longer working for + * the company. */ + LinphonePresenceActivityPermanentAbsence, + + /** The person is occupying himself or herself in amusement, sport, or other recreation. */ + LinphonePresenceActivityPlaying, + + /** The person is giving a presentation, lecture, or participating in a formal round-table discussion. */ + LinphonePresenceActivityPresentation, + + /** The person is visiting stores in search of goods or services. */ + LinphonePresenceActivityShopping, + + /** The person is sleeping.*/ + LinphonePresenceActivitySleeping, + + /** The person is observing an event, such as a sports event. */ + LinphonePresenceActivitySpectator, + + /** The person is controlling a vehicle, watercraft, or plane. */ + LinphonePresenceActivitySteering, + + /** The person is on a business or personal trip, but not necessarily in-transit. */ + LinphonePresenceActivityTravel, + + /** The person is watching television. */ + LinphonePresenceActivityTV, + + /** The activity of the person is unknown. */ + LinphonePresenceActivityUnknown, + + /** A period of time devoted to pleasure, rest, or relaxation. */ + LinphonePresenceActivityVacation, + + /** The person is engaged in, typically paid, labor, as part of a profession or job. */ + LinphonePresenceActivityWorking, + + /** The person is participating in religious rites. */ + LinphonePresenceActivityWorship +} LinphonePresenceActivityType; + +/** + * Structure holding the information about the presence of a person. + */ +struct _LinphonePresenceModel; + +/** + * Presence model type holding information about the presence of a person. + */ +typedef struct _LinphonePresenceModel LinphonePresenceModel; + +/** + * Structure holding the information about a presence service. + */ +struct _LinphonePresenceService; + +/** + * Structure holding the information about a presence person. + */ +struct _LinphonePresencePerson; + +/** + * Presence person holding information about a presence person. + */ +typedef struct _LinphonePresencePerson LinphonePresencePerson; + +/** + * Presence service type holding information about a presence service. + */ +typedef struct _LinphonePresenceService LinphonePresenceService; + +/** + * Structure holding the information about a presence activity. + */ +struct _LinphonePresenceActivity; + +/** + * Presence activity type holding information about a presence activity. + */ +typedef struct _LinphonePresenceActivity LinphonePresenceActivity; + +/** + * Structure holding the information about a presence note. + */ +struct _LinphonePresenceNote; + +/** + * Presence note type holding information about a presence note. + */ +typedef struct _LinphonePresenceNote LinphonePresenceNote; + + + +/***************************************************************************** + * HELPER FUNCTIONS TO EASE ACCESS IN MOST SIMPLER CASES * + ****************************************************************************/ + +/** + * Creates a presence model specifying an activity. + * @param[in] activity The activity to set for the created presence model. + * @param[in] description An additional description of the activity (mainly useful for the 'other' activity). Set it to NULL to not add a description. + * @returns The created presence model, or NULL if an error occured. + * @see linphone_presence_model_new + * @see linphone_presence_model_new_with_activity_and_note + * + * The created presence model has the activity specified in the parameters. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivityType activity, const char *description); + +/** + * Creates a presence model specifying an activity and adding a note. + * @param[in] activity The activity to set for the created presence model. + * @param[in] description An additional description of the activity (mainly useful for the 'other' activity). Set it to NULL to not add a description. + * @param[in] note An additional note giving additional information about the contact presence. + * @param[in] lang The language the note is written in. It can be set to NULL in order to not specify the language of the note. + * @returns The created presence model, or NULL if an error occured. + * @see linphone_presence_model_new_with_activity + * @see linphone_presence_model_new_with_activity_and_note + * + * The created presence model has the activity and the note specified in the parameters. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivityType activity, const char *description, const char *note, const char *lang); + +/** + * Gets the basic status of a presence model. + * @param[in] model The #LinphonePresenceModel object to get the basic status from. + * @return The #LinphonePresenceBasicStatus of the #LinphonePresenceModel object given as parameter. + */ +LINPHONE_PUBLIC LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model); + +/** + * Sets the basic status of a presence model. + * @param[in] model The #LinphonePresenceModel object for which to set the basic status. + * @param[in] basic_status The #LinphonePresenceBasicStatus to set for the #LinphonePresenceModel object. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status); + +/** + * Gets the timestamp of a presence model. + * @param[in] model The #LinphonePresenceModel object to get the timestamp from. + * @return The timestamp of the #LinphonePresenceModel object or -1 on error. + */ +LINPHONE_PUBLIC time_t linphone_presence_model_get_timestamp(const LinphonePresenceModel *model); + +/** + * Gets the contact of a presence model. + * @param[in] model The #LinphonePresenceModel object to get the contact from. + * @return A pointer to a dynamically allocated string containing the contact, or NULL if no contact is found. + * + * The returned string is to be freed by calling ms_free(). + */ +LINPHONE_PUBLIC char * linphone_presence_model_get_contact(const LinphonePresenceModel *model); + +/** + * Sets the contact of a presence model. + * @param[in] model The #LinphonePresenceModel object for which to set the contact. + * @param[in] contact The contact string to set. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact); + +/** + * Gets the first activity of a presence model (there is usually only one). + * @param[in] model The #LinphonePresenceModel object to get the activity from. + * @return A #LinphonePresenceActivity object if successful, NULL otherwise. + */ +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_model_get_activity(const LinphonePresenceModel *model); + +/** + * Sets the activity of a presence model (limits to only one activity). + * @param[in] model The #LinphonePresenceModel object for which to set the activity. + * @param[in] activity The #LinphonePresenceActivityType to set for the model. + * @param[in] description An additional description of the activity to set for the model. Can be NULL if no additional description is to be added. + * @return 0 if successful, a value < 0 in case of error. + * + * WARNING: This function will modify the basic status of the model according to the activity being set. + * If you don't want the basic status to be modified automatically, you can use the combination of linphone_presence_model_set_basic_status(), + * linphone_presence_model_clear_activities() and linphone_presence_model_add_activity(). + */ +LINPHONE_PUBLIC int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType activity, const char *description); + +/** + * Gets the number of activities included in the presence model. + * @param[in] model The #LinphonePresenceModel object to get the number of activities from. + * @return The number of activities included in the #LinphonePresenceModel object. + */ +LINPHONE_PUBLIC unsigned int linphone_presence_model_get_nb_activities(const LinphonePresenceModel *model); + +/** + * Gets the nth activity of a presence model. + * @param[in] model The #LinphonePresenceModel object to get the activity from. + * @param[in] idx The index of the activity to get (the first activity having the index 0). + * @return A pointer to a #LinphonePresenceActivity object if successful, NULL otherwise. + */ +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx); + +/** + * Adds an activity to a presence model. + * @param[in] model The #LinphonePresenceModel object for which to add an activity. + * @param[in] activity The #LinphonePresenceActivity object to add to the model. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivity *activity); + +/** + * Clears the activities of a presence model. + * @param[in] model The #LinphonePresenceModel object for which to clear the activities. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_model_clear_activities(LinphonePresenceModel *model); + +/** + * Gets the first note of a presence model (there is usually only one). + * @param[in] model The #LinphonePresenceModel object to get the note from. + * @param[in] lang The language of the note to get. Can be NULL to get a note that has no language specified or to get the first note whatever language it is written into. + * @return A pointer to a #LinphonePresenceNote object if successful, NULL otherwise. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang); + +/** + * Adds a note to a presence model. + * @param[in] model The #LinphonePresenceModel object to add a note to. + * @param[in] note_content The note to be added to the presence model. + * @param[in] lang The language of the note to be added. Can be NULL if no language is to be specified for the note. + * @return 0 if successful, a value < 0 in case of error. + * + * Only one note for each language can be set, so e.g. setting a note for the 'fr' language if there is only one will replace the existing one. + */ +LINPHONE_PUBLIC int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *note_content, const char *lang); + +/** + * Clears all the notes of a presence model. + * @param[in] model The #LinphonePresenceModel for which to clear notes. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_model_clear_notes(LinphonePresenceModel *model); + + +/***************************************************************************** + * PRESENCE MODEL FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * Creates a default presence model. + * @returns The created presence model, NULL on error. + * @see linphone_presence_model_new_with_activity + * @see linphone_presence_model_new_with_activity_and_note + * + * The created presence model is considered 'offline'. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_presence_model_new(void); + +/** + * Gets the number of services included in the presence model. + * @param[in] model The #LinphonePresenceModel object to get the number of services from. + * @return The number of services included in the #LinphonePresenceModel object. + */ +LINPHONE_PUBLIC unsigned int linphone_presence_model_get_nb_services(const LinphonePresenceModel *model); + +/** + * Gets the nth service of a presence model. + * @param[in] model The #LinphonePresenceModel object to get the service from. + * @param[in] idx The index of the service to get (the first service having the index 0). + * @return A pointer to a #LinphonePresenceService object if successful, NULL otherwise. + */ +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_model_get_nth_service(const LinphonePresenceModel *model, unsigned int idx); + +/** + * Adds a service to a presence model. + * @param[in] model The #LinphonePresenceModel object for which to add a service. + * @param[in] service The #LinphonePresenceService object to add to the model. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_model_add_service(LinphonePresenceModel *model, LinphonePresenceService *service); + +/** + * Clears the services of a presence model. + * @param[in] model The #LinphonePresenceModel object for which to clear the services. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_model_clear_services(LinphonePresenceModel *model); + +/** + * Gets the number of persons included in the presence model. + * @param[in] model The #LinphonePresenceModel object to get the number of persons from. + * @return The number of persons included in the #LinphonePresenceModel object. + */ +LINPHONE_PUBLIC unsigned int linphone_presence_model_get_nb_persons(const LinphonePresenceModel *model); + +/** + * Gets the nth person of a presence model. + * @param[in] model The #LinphonePresenceModel object to get the person from. + * @param[in] idx The index of the person to get (the first person having the index 0). + * @return A pointer to a #LinphonePresencePerson object if successful, NULL otherwise. + */ +LINPHONE_PUBLIC LinphonePresencePerson * linphone_presence_model_get_nth_person(const LinphonePresenceModel *model, unsigned int idx); + +/** + * Adds a person to a presence model. + * @param[in] model The #LinphonePresenceModel object for which to add a person. + * @param[in] person The #LinphonePresencePerson object to add to the model. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person); + +/** + * Clears the persons of a presence model. + * @param[in] model The #LinphonePresenceModel object for which to clear the persons. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_model_clear_persons(LinphonePresenceModel *model); + + +/***************************************************************************** + * PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * Creates a presence service. + * @param[in] id The id of the presence service to be created. Can be NULL to generate it automatically. + * @param[in] basic_status The #LinphonePresenceBasicStatus to set for the #LinphonePresenceService object. + * @param[in] contact The contact string to set. + * @returns The created presence service, NULL on error. + * + * The created presence service has the basic status 'closed'. + */ +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus, const char *contact); + +/** + * Gets the id of a presence service. + * @param[in] service The #LinphonePresenceService object to get the id from. + * @return A pointer to a dynamically allocated string containing the id, or NULL in case of error. + * + * The returned string is to be freed by calling ms_free(). + */ +LINPHONE_PUBLIC char * linphone_presence_service_get_id(const LinphonePresenceService *service); + +/** + * Sets the id of a presence service. + * @param[in] service The #LinphonePresenceService object for which to set the id. + * @param[in] id The id string to set. Can be NULL to generate it automatically. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_service_set_id(LinphonePresenceService *service, const char *id); + +/** + * Gets the basic status of a presence service. + * @param[in] service The #LinphonePresenceService object to get the basic status from. + * @return The #LinphonePresenceBasicStatus of the #LinphonePresenceService object given as parameter. + */ +LINPHONE_PUBLIC LinphonePresenceBasicStatus linphone_presence_service_get_basic_status(const LinphonePresenceService *service); + +/** + * Sets the basic status of a presence service. + * @param[in] service The #LinphonePresenceService object for which to set the basic status. + * @param[in] basic_status The #LinphonePresenceBasicStatus to set for the #LinphonePresenceService object. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_service_set_basic_status(LinphonePresenceService *service, LinphonePresenceBasicStatus basic_status); + +/** + * Gets the contact of a presence service. + * @param[in] service The #LinphonePresenceService object to get the contact from. + * @return A pointer to a dynamically allocated string containing the contact, or NULL if no contact is found. + * + * The returned string is to be freed by calling ms_free(). + */ +LINPHONE_PUBLIC char * linphone_presence_service_get_contact(const LinphonePresenceService *service); + +/** + * Sets the contact of a presence service. + * @param[in] service The #LinphonePresenceService object for which to set the contact. + * @param[in] contact The contact string to set. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_service_set_contact(LinphonePresenceService *service, const char *contact); + +/** + * Gets the number of notes included in the presence service. + * @param[in] service The #LinphonePresenceService object to get the number of notes from. + * @return The number of notes included in the #LinphonePresenceService object. + */ +LINPHONE_PUBLIC unsigned int linphone_presence_service_get_nb_notes(const LinphonePresenceService *service); + +/** + * Gets the nth note of a presence service. + * @param[in] service The #LinphonePresenceService object to get the note from. + * @param[in] idx The index of the note to get (the first note having the index 0). + * @return A pointer to a #LinphonePresenceNote object if successful, NULL otherwise. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_service_get_nth_note(const LinphonePresenceService *service, unsigned int idx); + +/** + * Adds a note to a presence service. + * @param[in] service The #LinphonePresenceService object for which to add a note. + * @param[in] note The #LinphonePresenceNote object to add to the service. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note); + +/** + * Clears the notes of a presence service. + * @param[in] service The #LinphonePresenceService object for which to clear the notes. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_service_clear_notes(LinphonePresenceService *service); + + +/***************************************************************************** + * PRESENCE PERSON FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * Creates a presence person. + * @param[in] id The id of the presence person to be created. Can be NULL to generate it automatically. + * @returns The created presence person, NULL on error. + */ +LINPHONE_PUBLIC LinphonePresencePerson * linphone_presence_person_new(const char *id); + +/** + * Gets the id of a presence person. + * @param[in] person The #LinphonePresencePerson object to get the id from. + * @return A pointer to a dynamically allocated string containing the id, or NULL in case of error. + * + * The returned string is to be freed by calling ms_free(). + */ +LINPHONE_PUBLIC char * linphone_presence_person_get_id(const LinphonePresencePerson *person); + +/** + * Sets the id of a presence person. + * @param[in] person The #LinphonePresencePerson object for which to set the id. + * @param[in] id The id string to set. Can be NULL to generate it automatically. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_person_set_id(LinphonePresencePerson *person, const char *id); + +/** + * Gets the number of activities included in the presence person. + * @param[in] person The #LinphonePresencePerson object to get the number of activities from. + * @return The number of activities included in the #LinphonePresencePerson object. + */ +LINPHONE_PUBLIC unsigned int linphone_presence_person_get_nb_activities(const LinphonePresencePerson *person); + +/** + * Gets the nth activity of a presence person. + * @param[in] person The #LinphonePresencePerson object to get the activity from. + * @param[in] idx The index of the activity to get (the first activity having the index 0). + * @return A pointer to a #LinphonePresenceActivity object if successful, NULL otherwise. + */ +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_person_get_nth_activity(const LinphonePresencePerson *person, unsigned int idx); + +/** + * Adds an activity to a presence person. + * @param[in] person The #LinphonePresencePerson object for which to add an activity. + * @param[in] activity The #LinphonePresenceActivity object to add to the person. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_person_add_activity(LinphonePresencePerson *person, LinphonePresenceActivity *activity); + +/** + * Clears the activities of a presence person. + * @param[in] person The #LinphonePresencePerson object for which to clear the activities. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_person_clear_activities(LinphonePresencePerson *person); + +/** + * Gets the number of notes included in the presence person. + * @param[in] person The #LinphonePresencePerson object to get the number of notes from. + * @return The number of notes included in the #LinphonePresencePerson object. + */ +LINPHONE_PUBLIC unsigned int linphone_presence_person_get_nb_notes(const LinphonePresencePerson *person); + +/** + * Gets the nth note of a presence person. + * @param[in] person The #LinphonePresencePerson object to get the note from. + * @param[in] idx The index of the note to get (the first note having the index 0). + * @return A pointer to a #LinphonePresenceNote object if successful, NULL otherwise. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_person_get_nth_note(const LinphonePresencePerson *person, unsigned int idx); + +/** + * Adds a note to a presence person. + * @param[in] person The #LinphonePresencePerson object for which to add a note. + * @param[in] note The #LinphonePresenceNote object to add to the person. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note); + +/** + * Clears the notes of a presence person. + * @param[in] person The #LinphonePresencePerson object for which to clear the notes. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_person_clear_notes(LinphonePresencePerson *person); + +/** + * Gets the number of activities notes included in the presence person. + * @param[in] person The #LinphonePresencePerson object to get the number of activities notes from. + * @return The number of activities notes included in the #LinphonePresencePerson object. + */ +LINPHONE_PUBLIC unsigned int linphone_presence_person_get_nb_activities_notes(const LinphonePresencePerson *person); + +/** + * Gets the nth activities note of a presence person. + * @param[in] person The #LinphonePresencePerson object to get the activities note from. + * @param[in] idx The index of the activities note to get (the first note having the index 0). + * @return A pointer to a #LinphonePresenceNote object if successful, NULL otherwise. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_person_get_nth_activities_note(const LinphonePresencePerson *person, unsigned int idx); + +/** + * Adds an activities note to a presence person. + * @param[in] person The #LinphonePresencePerson object for which to add an activities note. + * @param[in] note The #LinphonePresenceNote object to add to the person. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_person_add_activities_note(LinphonePresencePerson *person, LinphonePresenceNote *note); + +/** + * Clears the activities notes of a presence person. + * @param[in] person The #LinphonePresencePerson object for which to clear the activities notes. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_person_clear_activities_notes(LinphonePresencePerson *person); + + +/***************************************************************************** + * PRESENCE ACTIVITY FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * Creates a presence activity. + * @param[in] acttype The #LinphonePresenceActivityType to set for the activity. + * @param[in] description An additional description of the activity to set for the activity. Can be NULL if no additional description is to be added. + * @returns The created presence activity, NULL on error. + */ +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_presence_activity_new(LinphonePresenceActivityType acttype, const char *description); + +/** + * Gets the string representation of a presence activity. + * @param[in] activity A pointer to the #LinphonePresenceActivity object for which to get a string representation. + * @return A pointer a dynamically allocated string representing the given activity. + * + * The returned string is to be freed by calling ms_free(). + */ +LINPHONE_PUBLIC char * linphone_presence_activity_to_string(const LinphonePresenceActivity * activity); + +/** + * Gets the activity type of a presence activity. + * @param[in] activity A pointer to the #LinphonePresenceActivity for which to get the type. + * @return The #LinphonePresenceActivityType of the activity. + */ +LINPHONE_PUBLIC LinphonePresenceActivityType linphone_presence_activity_get_type(const LinphonePresenceActivity *activity); + +/** + * Sets the type of activity of a presence activity. + * @param[in] activity The #LinphonePresenceActivity for which to set for the activity type. + * @param[in] acttype The activity type to set for the activity. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_activity_set_type(LinphonePresenceActivity *activity, LinphonePresenceActivityType acttype); + +/** + * Gets the description of a presence activity. + * @param[in] activity A pointer to the #LinphonePresenceActivity for which to get the description. + * @return A pointer to the description string of the presence activity, or NULL if no description is specified. + */ +LINPHONE_PUBLIC const char * linphone_presence_activity_get_description(const LinphonePresenceActivity *activity); + +/** + * Sets the description of a presence activity. + * @param[in] activity The #LinphonePresenceActivity object for which to set the description. + * @param[in] description An additional description of the activity. Can be NULL if no additional description is to be added. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_activity_set_description(LinphonePresenceActivity *activity, const char *description); + + +/***************************************************************************** + * PRESENCE NOTE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +/** + * Creates a presence note. + * @param[in] content The content of the note to be created. + * @param[in] lang The language of the note to be created. Can be NULL if no language is to be specified for the note. + * @returns The created presence note, NULL on error. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_presence_note_new(const char *content, const char *lang); + +/** + * Gets the content of a presence note. + * @param[in] note A pointer to the #LinphonePresenceNote for which to get the content. + * @return A pointer to the content of the presence note. + */ +LINPHONE_PUBLIC const char * linphone_presence_note_get_content(const LinphonePresenceNote *note); + +/** + * Sets the content of a presence note. + * @param[in] note The #LinphonePresenceNote object for which to set the content. + * @param[in] content The content of the note. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_note_set_content(LinphonePresenceNote *note, const char *content); + +/** + * Gets the language of a presence note. + * @param[in] note A pointer to the #LinphonePresenceNote for which to get the language. + * @return A pointer to the language string of the presence note, or NULL if no language is specified. + */ +LINPHONE_PUBLIC const char * linphone_presence_note_get_lang(const LinphonePresenceNote *note); + +/** + * Sets the language of a presence note. + * @param[in] note The #LinphonePresenceNote object for which to set the language. + * @param[in] lang The language of the note. + * @return 0 if successful, a value < 0 in case of error. + */ +LINPHONE_PUBLIC int linphone_presence_note_set_lang(LinphonePresenceNote *note, const char *lang); + + +/***************************************************************************** + * PRESENCE INTERNAL FUNCTIONS FOR WRAPPERS IN OTHER PROGRAMMING LANGUAGES * + ****************************************************************************/ + +/** + * Increase the reference count of the #LinphonePresenceModel object. + * @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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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 CORE FUNCTIONS RELATED TO PRESENCE * + ****************************************************************************/ + +/** + * Create a LinphonePresenceActivity with the given type and description. + * @param[in] lc #LinphoneCore object. + * @param[in] acttype The #LinphonePresenceActivityType to set for the activity. + * @param[in] description An additional description of the activity to set for the activity. Can be NULL if no additional description is to be added. + * @returns The created #LinphonePresenceActivity object. + */ +LINPHONE_PUBLIC LinphonePresenceActivity * linphone_core_create_presence_activity(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description); + +/** + * Create a default LinphonePresenceModel. + * @param[in] lc #LinphoneCore object. + * @returns The created #LinphonePresenceModel object. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_core_create_presence_model(LinphoneCore *lc); + +/** + * Create a LinphonePresenceModel with the given activity type and activity description. + * @param[in] lc #LinphoneCore object. + * @param[in] acttype The #LinphonePresenceActivityType to set for the activity of the created model. + * @param[in] description An additional description of the activity to set for the activity. Can be NULL if no additional description is to be added. + * @returns The created #LinphonePresenceModel object. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_core_create_presence_model_with_activity(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description); + +/** + * Create a LinphonePresenceModel with the given activity type, activity description, note content and note language. + * @param[in] lc #LinphoneCore object. + * @param[in] acttype The #LinphonePresenceActivityType to set for the activity of the created model. + * @param[in] description An additional description of the activity to set for the activity. Can be NULL if no additional description is to be added. + * @param[in] note The content of the note to be added to the created model. + * @param[in] lang The language of the note to be added to the created model. + * @returns The created #LinphonePresenceModel object. + */ +LINPHONE_PUBLIC LinphonePresenceModel * linphone_core_create_presence_model_with_activity_and_note(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description, const char *note, const char *lang); + +/** + * Create a LinphonePresenceNote with the given content and language. + * @param[in] lc #LinphoneCore object. + * @param[in] content The content of the note to be created. + * @param[in] lang The language of the note to be created. + * @returns The created #LinphonePresenceNote object. + */ +LINPHONE_PUBLIC LinphonePresenceNote * linphone_core_create_presence_note(LinphoneCore *lc, const char *content, const char *lang); + +/** + * Create a LinphonePresencePerson with the given id. + * @param[in] lc #LinphoneCore object + * @param[in] id The id of the person to be created. + * @returns The created #LinphonePresencePerson object. + */ +LINPHONE_PUBLIC LinphonePresencePerson * linphone_core_create_presence_person(LinphoneCore *lc, const char *id); + +/** + * Create a LinphonePresenceService with the given id, basic status and contact. + * @param[in] lc #LinphoneCore object. + * @param[in] id The id of the service to be created. + * @param[in] basic_status The basic status of the service to be created. + * @param[in] contact A string containing a contact information corresponding to the service to be created. + * @returns The created #LinphonePresenceService object. + */ +LINPHONE_PUBLIC LinphonePresenceService * linphone_core_create_presence_service(LinphoneCore *lc, const char *id, LinphonePresenceBasicStatus basic_status, const char *contact); + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* LINPHONEPRESENCE_H_ */ diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index ca65fd1ff..d7a5d14f3 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -34,6 +34,9 @@ #include #include #include +#if _MSC_VER +#include +#endif #endif /*_WIN32_WCE*/ @@ -140,18 +143,20 @@ LpItem *lp_section_find_item(const LpSection *sec, const char *name){ void lp_config_parse(LpConfig *lpconfig, FILE *file){ char tmp[MAX_LEN]= {'\0'}; LpSection *cur=NULL; + char *pos1,*pos2; + int nbs; + char secname[MAX_LEN]; + char key[MAX_LEN]; + LpItem *item; if (file==NULL) return; while(fgets(tmp,MAX_LEN,file)!=NULL){ tmp[sizeof(tmp) -1] = '\0'; - char *pos1,*pos2; pos1=strchr(tmp,'['); if (pos1!=NULL && is_first_char(tmp,pos1) ){ pos2=strchr(pos1,']'); if (pos2!=NULL){ - int nbs; - char secname[MAX_LEN]; secname[0]='\0'; /* found section */ *pos2='\0'; @@ -171,7 +176,6 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ }else { pos1=strchr(tmp,'='); if (pos1!=NULL){ - char key[MAX_LEN]; key[0]='\0'; *pos1='\0'; @@ -192,7 +196,7 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){ /* found a pair key,value */ if (cur!=NULL){ - LpItem *item=lp_section_find_item(cur,key); + item=lp_section_find_item(cur,key); if (item==NULL){ lp_section_add_item(cur,lp_item_new(key,pos1)); }else{ @@ -216,23 +220,26 @@ LpConfig * lp_config_new(const char *filename){ LpConfig *lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename) { LpConfig *lpconfig=lp_new0(LpConfig,1); + if (config_filename!=NULL){ ms_message("Using (r/w) config information from %s", config_filename); lpconfig->filename=ortp_strdup(config_filename); lpconfig->file=fopen(config_filename,"r+"); if (lpconfig->file!=NULL){ - struct stat fileStat; lp_config_parse(lpconfig,lpconfig->file); fclose(lpconfig->file); -#if !defined(_WIN32_WCE) - if ((stat(config_filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) { - /* make existing configuration files non-group/world-accessible */ - if (chmod(config_filename, S_IRUSR | S_IWUSR) == -1) { - ms_warning("unable to correct permissions on " - "configuration file: %s", strerror(errno)); +#if !defined(WIN32) + { + struct stat fileStat; + if ((stat(config_filename,&fileStat) == 0) && (S_ISREG(fileStat.st_mode))) { + /* make existing configuration files non-group/world-accessible */ + if (chmod(config_filename, S_IRUSR | S_IWUSR) == -1) { + ms_warning("unable to correct permissions on " + "configuration file: %s", strerror(errno)); + } } } -#endif /*_WIN32_WCE*/ +#endif /*WIN32*/ lpconfig->file=NULL; lpconfig->modified=0; } diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index 43f761adb..f413bf7a6 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -24,9 +24,13 @@ #ifndef LPCONFIG_H #define LPCONFIG_H - +#include #include +#ifndef LINPHONE_PUBLIC + #define LINPHONE_PUBLIC MS2_PUBLIC +#endif + /** * The LpConfig object is used to manipulate a configuration file. * @@ -72,7 +76,7 @@ extern "C" { * @param filename the filename of the config file to read to fill the instantiated LpConfig * @see lp_config_new_with_factory */ -LpConfig * lp_config_new(const char *filename); +LINPHONE_PUBLIC LpConfig * lp_config_new(const char *filename); /** * Instantiates a LpConfig object from a user config file and a factory config file. @@ -86,17 +90,24 @@ LpConfig * lp_config_new(const char *filename); * Therefore the configuration parameters defined in the user config file will be overwritten by the parameters * defined in the factory config file. */ -LpConfig * lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename); +LINPHONE_PUBLIC LpConfig * lp_config_new_with_factory(const char *config_filename, const char *factory_config_filename); + +/** + * Reads a user config file and fill the LpConfig with the read config values. + * @ingroup misc + * @param lpconfig The LpConfig object to fill with the content of the file + * @param filename The filename of the config file to read to fill the LpConfig + */ +LINPHONE_PUBLIC int lp_config_read_file(LpConfig *lpconfig, const char *filename); -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. **/ -const char *lp_config_get_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_string); -int lp_config_read_file(LpConfig *lpconfig, const char *filename); +LINPHONE_PUBLIC const char *lp_config_get_string(const LpConfig *lpconfig, const char *section, const char *key, const char *default_string); + /** * Retrieves a configuration item as a range, given its section, key, and default min and max values. * @@ -104,14 +115,15 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename); * @return TRUE if the value is successfully parsed as a range, FALSE otherwise. * If FALSE is returned, min and max are filled respectively with default_min and default_max values. */ -bool_t lp_config_get_range(const LpConfig *lpconfig, const char *section, const char *key, int *min, int *max, int default_min, int default_max); +LINPHONE_PUBLIC bool_t lp_config_get_range(const LpConfig *lpconfig, const char *section, const char *key, int *min, int *max, int default_min, int default_max); + /** * 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. **/ -int lp_config_get_int(const LpConfig *lpconfig,const char *section, const char *key, int default_value); +LINPHONE_PUBLIC int lp_config_get_int(const LpConfig *lpconfig,const char *section, const char *key, int default_value); /** * Retrieves a configuration item as a 64 bit integer, given its section, key, and default value. @@ -119,35 +131,36 @@ int lp_config_get_int(const LpConfig *lpconfig,const char *section, const char * * @ingroup misc * The default integer value is returned if the config item isn't found. **/ -int64_t lp_config_get_int64(const LpConfig *lpconfig,const char *section, const char *key, int64_t default_value); +LINPHONE_PUBLIC int64_t lp_config_get_int64(const LpConfig *lpconfig,const char *section, const char *key, int64_t default_value); - -int lp_config_read_file(LpConfig *lpconfig, const char *filename); /** * 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. **/ -float lp_config_get_float(const LpConfig *lpconfig,const char *section, const char *key, float default_value); +LINPHONE_PUBLIC float lp_config_get_float(const LpConfig *lpconfig,const char *section, const char *key, float default_value); + /** * Sets a string config item * * @ingroup misc **/ -void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); +LINPHONE_PUBLIC void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); + /** * Sets a range config item * * @ingroup misc */ -void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value); +LINPHONE_PUBLIC void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value); + /** * Sets an integer config item * * @ingroup misc **/ -void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value); +LINPHONE_PUBLIC void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value); /** * Sets an integer config item, but store it as hexadecimal @@ -161,38 +174,43 @@ void lp_config_set_int_hex(LpConfig *lpconfig,const char *section, const char *k * * @ingroup misc **/ -void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value); +LINPHONE_PUBLIC void lp_config_set_int64(LpConfig *lpconfig,const char *section, const char *key, int64_t value); /** * Sets a float config item * * @ingroup misc **/ -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 **/ -int lp_config_sync(LpConfig *lpconfig); +LINPHONE_PUBLIC int lp_config_sync(LpConfig *lpconfig); + /** * Returns 1 if a given section is present in the configuration. * * @ingroup misc **/ -int lp_config_has_section(const LpConfig *lpconfig, const char *section); +LINPHONE_PUBLIC int lp_config_has_section(const LpConfig *lpconfig, const char *section); + /** * Removes every pair of key,value in a section and remove the section. * * @ingroup misc **/ -void lp_config_clean_section(LpConfig *lpconfig, const char *section); +LINPHONE_PUBLIC void lp_config_clean_section(LpConfig *lpconfig, const char *section); + /** * Call a function for each section present in the configuration. * * @ingroup misc **/ void lp_config_for_each_section(const LpConfig *lpconfig, void (*callback)(const char *section, void *ctx), void *ctx); + /** * Call a function for each entry present in a section configuration. * diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 765543f7a..360f28f0a 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -48,8 +48,10 @@ static void create_chat_message(char **argv, void *data){ char tmp2[80]={0}; if(atoi(argv[3])==LinphoneChatMessageIncoming){ + new_message->dir=LinphoneChatMessageIncoming; from=linphone_address_new(argv[2]); } else { + new_message->dir=LinphoneChatMessageOutgoing; from=linphone_address_new(argv[1]); } linphone_chat_message_set_from(new_message,from); @@ -69,13 +71,24 @@ static void create_chat_message(char **argv, void *data){ ret.tm_isdst=-1; } new_message->time=argv[5]!=NULL ? mktime(&ret) : time(NULL); + new_message->is_read=atoi(argv[6]); new_message->state=atoi(argv[7]); + new_message->storage_id=atoi(argv[0]); + new_message->external_body_url=argv[8]?ms_strdup(argv[8]):NULL; cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); } +// Called when fetching all conversations from database +static int callback_all(void *data, int argc, char **argv, char **colName){ + LinphoneCore* lc = (LinphoneCore*) data; + char* address = argv[0]; + linphone_core_create_chat_room(lc, address); + return 0; +} + static int callback(void *data, int argc, char **argv, char **colName){ - create_chat_message(argv,data); - return 0; + create_chat_message(argv,data); + return 0; } void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){ @@ -91,26 +104,41 @@ void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom void linphone_sql_request(sqlite3* db,const char *stmt){ char* errmsg=NULL; int ret; - ret=sqlite3_exec(db,stmt,0,0,&errmsg); + ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg); if(ret != SQLITE_OK) { ms_error("linphone_sql_request: error sqlite3_exec(): %s.\n", errmsg); sqlite3_free(errmsg); } } -void linphone_chat_message_store(LinphoneChatMessage *msg){ +// Process the request to fetch all chat contacts +void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg); + if(ret != SQLITE_OK) { + ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.\n", errmsg); + sqlite3_free(errmsg); + } +} + +unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room); + int id=0; + if (lc->db){ char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); char datebuf[26]; - char *buf=sqlite3_mprintf("insert into history values(NULL,%Q,%Q,%i,%Q,%Q,%i,%i);", - local_contact,peer,msg->dir,msg->message,my_ctime_r(&msg->time,datebuf),msg->is_read,msg->state); + char *buf=sqlite3_mprintf("insert into history values(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q);", + local_contact,peer,msg->dir,msg->message,my_ctime_r(&msg->time,datebuf),msg->is_read,msg->state,msg->external_body_url); linphone_sql_request(lc->db,buf); sqlite3_free(buf); ms_free(local_contact); ms_free(peer); + id = (unsigned int) sqlite3_last_insert_rowid (lc->db); } + return id; } void linphone_chat_message_store_state(LinphoneChatMessage *msg){ @@ -138,6 +166,16 @@ void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ ms_free(peer); } +void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + + if (lc->db==NULL) return ; + + char *buf=sqlite3_mprintf("update history set url=%Q where id=%i;",msg->external_body_url,msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); +} + int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ LinphoneCore *lc=linphone_chat_room_get_lc(cr); int numrows=0; @@ -159,6 +197,16 @@ int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ return numrows; } +void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + LinphoneCore *lc=cr->lc; + + if (lc->db==NULL) return ; + + char *buf=sqlite3_mprintf("delete from history where id = %i;", msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); +} + void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ LinphoneCore *lc=cr->lc; @@ -174,11 +222,16 @@ void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ LinphoneCore *lc=linphone_chat_room_get_lc(cr); MSList *ret; + char *buf; + char *peer; if (lc->db==NULL) return NULL; - char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); cr->messages_hist = NULL; - char *buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",peer,nb_message); + if (nb_message > 0) + buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC limit %i ;",peer,nb_message); + else + buf=sqlite3_mprintf("select * from history where remoteContact = %Q order by id DESC;",peer); linphone_sql_request_message(lc->db,buf,cr); sqlite3_free(buf); ret=cr->messages_hist; @@ -202,6 +255,27 @@ void linphone_create_table(sqlite3* db){ } } +void linphone_update_table(sqlite3* db) { + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg); + if(ret != SQLITE_OK) { + ms_warning("Table already up to date: %s.\n", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table updated successfuly."); + } +} + +void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { + char *buf; + + if (lc->db==NULL) return; + buf=sqlite3_mprintf("SELECT remoteContact FROM history Group By remoteContact;"); + linphone_sql_request_all(lc->db,buf,lc); + sqlite3_free(buf); +} + void linphone_core_message_storage_init(LinphoneCore *lc){ int ret; const char *errmsg; @@ -213,7 +287,11 @@ void linphone_core_message_storage_init(LinphoneCore *lc){ sqlite3_close(db); } linphone_create_table(db); + linphone_update_table(db); lc->db=db; + + // Create a chatroom for each contact in the chat history + linphone_message_storage_init_chat_rooms(lc); } void linphone_core_message_storage_close(LinphoneCore *lc){ @@ -225,7 +303,8 @@ void linphone_core_message_storage_close(LinphoneCore *lc){ #else -void linphone_chat_message_store(LinphoneChatMessage *cr){ +unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){ + return 0; } void linphone_chat_message_store_state(LinphoneChatMessage *cr){ @@ -238,15 +317,24 @@ MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ return NULL; } +void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +} + void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ } +void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { +} + void linphone_core_message_storage_init(LinphoneCore *lc){ } void linphone_core_message_storage_close(LinphoneCore *lc){ } +void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +} + int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ return 0; } diff --git a/coreapi/misc.c b/coreapi/misc.c index 36fe7ae3f..c96fde835 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -32,7 +32,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include +#if _MSC_VER +#include +#else #include +#endif #include #endif /*_WIN32_WCE*/ @@ -44,6 +48,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #endif #include +#if _MSC_VER +#define snprintf _snprintf +#define popen _popen +#define pclose _pclose +#endif #if !defined(WIN32) @@ -415,31 +424,38 @@ static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t ad return 0; } -int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){ - struct addrinfo hints,*res=NULL; - int family = PF_INET; - int port_int = 3478; - int ret; - char port[6]; - char host[NI_MAXHOST]; +int linphone_parse_host_port(const char *input, char *host, size_t hostlen, int *port){ + char tmphost[NI_MAXHOST]={0}; char *p1, *p2; - if ((sscanf(server, "[%64[^]]]:%d", host, &port_int) == 2) || (sscanf(server, "[%64[^]]]", host) == 1)) { - family = PF_INET6; + + if ((sscanf(input, "[%64[^]]]:%d", tmphost, port) == 2) || (sscanf(input, "[%64[^]]]", tmphost) == 1)) { + } else { - p1 = strchr(server, ':'); - p2 = strrchr(server, ':'); - if (p1 && p2 && (p1 != p2)) { - family = PF_INET6; - host[NI_MAXHOST-1]='\0'; - strncpy(host, server, sizeof(host) - 1); - } else if (sscanf(server, "%[^:]:%d", host, &port_int) != 2) { - host[NI_MAXHOST-1]='\0'; - strncpy(host, server, sizeof(host) - 1); + p1 = strchr(input, ':'); + p2 = strrchr(input, ':'); + if (p1 && p2 && (p1 != p2)) {/* an ipv6 address without port*/ + strncpy(tmphost, input, sizeof(tmphost) - 1); + } else if (sscanf(input, "%[^:]:%d", tmphost, port) != 2) { + /*no port*/ + strncpy(tmphost, input, sizeof(tmphost) - 1); } } + strncpy(host,tmphost,hostlen); + return 0; +} + +int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port){ + struct addrinfo hints,*res=NULL; + char port[6]; + char host[NI_MAXHOST]; + int port_int=default_port; + int ret; + + linphone_parse_host_port(server,host,sizeof(host),&port_int); + snprintf(port, sizeof(port), "%d", port_int); memset(&hints,0,sizeof(hints)); - hints.ai_family=family; + hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_DGRAM; hints.ai_protocol=IPPROTO_UDP; ret=getaddrinfo(host,port,&hints,&res); @@ -486,8 +502,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ return -1; } if (server!=NULL){ - struct sockaddr_storage ss; - socklen_t ss_len; + const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc); ortp_socket_t sock1=-1, sock2=-1; int loops=0; bool_t video_enabled=linphone_core_video_enabled(lc); @@ -497,8 +512,8 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ double elapsed; int ret=0; - if (parse_hostname_to_addr(server,&ss,&ss_len)<0){ - ms_error("Fail to parser stun server address: %s",server); + if (ai==NULL){ + ms_error("Could not obtain stun server addrinfo."); return -1; } if (lc->vtable.display_status!=NULL) @@ -513,24 +528,20 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ } got_audio=FALSE; got_video=FALSE; - gettimeofday(&init,NULL); + ortp_gettimeofday(&init,NULL); do{ int id; if (loops%20==0){ ms_message("Sending stun requests..."); - sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE); - sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE); + sendStunRequest(sock1,ai->ai_addr,ai->ai_addrlen,11,TRUE); + sendStunRequest(sock1,ai->ai_addr,ai->ai_addrlen,1,FALSE); if (sock2!=-1){ - sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE); - sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE); + sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,22,TRUE); + sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,2,FALSE); } } -#ifdef WIN32 - Sleep(10); -#else - usleep(10000); -#endif + ms_usleep(10000); if (recvStunResponse(sock1,ac->addr, &ac->port,&id)>0){ @@ -550,7 +561,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ cone_video=TRUE; got_video=TRUE; } - gettimeofday(&cur,NULL); + ortp_gettimeofday(&cur,NULL); elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0); if (elapsed>2000) { ms_message("Stun responses timeout, going ahead."); @@ -594,9 +605,10 @@ int linphone_core_get_edge_ptime(LinphoneCore *lc){ } void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params){ + int threshold; if (ping_time_ms>0 && lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){ ms_message("Stun server ping time is %i ms",ping_time_ms); - int threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500); + threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500); if (ping_time_ms>threshold){ /* we might be in a 2G network*/ @@ -610,13 +622,60 @@ void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, Linphone } } +static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addrinfo *addrinfo){ + if (lc->net_conf.stun_addrinfo){ + freeaddrinfo(lc->net_conf.stun_addrinfo); + lc->net_conf.stun_addrinfo=NULL; + } + if (addrinfo){ + ms_message("Stun server resolution successful."); + }else{ + ms_warning("Stun server resolution failed."); + } + lc->net_conf.stun_addrinfo=addrinfo; + lc->net_conf.stun_res=NULL; +} +void linphone_core_resolve_stun_server(LinphoneCore *lc){ + 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); + } +} + +/* + * This function returns the addrinfo representation of the stun server address. + * It is critical not to block for a long time if it can't be resolved, otherwise this stucks the main thread when making a call. + * On the contrary, a fully asynchronous call initiation is complex to develop. + * The compromise is then: + * - have a cache of the stun server addrinfo + * - this cached value is returned when it is non-null + * - an asynchronous resolution is asked each time this function is called to ensure frequent refreshes of the cached value. + * - if no cached value exists, block for a short time; this case must be unprobable because the resolution will be asked each time the stun server value is + * changed. +**/ +const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc){ + const char *server=linphone_core_get_stun_server(lc); + if (server){ + int wait_ms=0; + int wait_limit=1000; + linphone_core_resolve_stun_server(lc); + while (!lc->net_conf.stun_addrinfo && lc->net_conf.stun_res!=NULL && wait_mssal); + ms_usleep(50000); + wait_ms+=50; + } + } + return lc->net_conf.stun_addrinfo; +} int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) { char local_addr[64]; - struct sockaddr_storage ss; - socklen_t ss_len; + const struct addrinfo *ai; IceCheckList *audio_check_list; IceCheckList *video_check_list; const char *server = linphone_core_get_stun_server(lc); @@ -630,16 +689,16 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ms_warning("stun support is not implemented for ipv6"); return -1; } - - if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) { - ms_error("Fail to parser stun server address: %s", server); + ai=linphone_core_get_stun_server_addrinfo(lc); + if (ai==NULL){ + ms_warning("Fail to resolve STUN server for ICE gathering."); return -1; } if (lc->vtable.display_status != NULL) lc->vtable.display_status(lc, _("ICE local candidates gathering in progress...")); /* Gather local host candidates. */ - if (linphone_core_get_local_ip_for(AF_INET, server, local_addr) < 0) { + if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) { ms_error("Fail to get local ip"); return -1; } @@ -657,7 +716,7 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ms_message("ICE: gathering candidate from [%s]",server); /* Gather local srflx candidates. */ - ice_session_gather_candidates(call->ice_session, ss, ss_len); + ice_session_gather_candidates(call->ice_session, ai->ai_addr, ai->ai_addrlen); return 0; } @@ -903,6 +962,12 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, ice_check_list_set_state(cl, ICL_Failed); } else if (stream->rtp_port == 0) { ice_session_remove_check_list(call->ice_session, cl); +#ifdef VIDEO_ENABLED + if (stream->type==SalVideo && call->videostream){ + video_stream_stop(call->videostream); + call->videostream=NULL; + } +#endif } else { if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); @@ -1114,7 +1179,8 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul ms_error("getnameinfo error: %s",strerror(errno)); } close_socket(sock); - ms_message("Local interface to reach %s is %s.",dest,result); + + return 0; } @@ -1134,7 +1200,6 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ * try to find 'the' running interface with getifaddrs*/ #ifdef HAVE_GETIFADDRS - /*we use getifaddrs for lookup of default interface */ int found_ifs; @@ -1149,26 +1214,102 @@ int linphone_core_get_local_ip_for(int type, const char *dest, char *result){ return 0; } -#ifndef WIN32 -#include - - - -void _linphone_core_configure_resolver(){ -/*bionic declares _res but does not define nor export it !!*/ -#ifdef ANDROID - /*timeout and attempts are the same as retrans and retry, but are android specific names.*/ - setenv("RES_OPTIONS","timeout:2 attempts:2 retrans:2 retry:2",1); -#else - res_init(); - _res.retrans=2; /*retransmit every two seconds*/ - _res.retry=2; /*only two times per DNS server*/ -#endif -} - -#else void _linphone_core_configure_resolver(){ } -#endif +SalReason linphone_reason_to_sal(LinphoneReason reason){ + switch(reason){ + case LinphoneReasonNone: + return SalReasonUnknown; + case LinphoneReasonNoResponse: + return SalReasonUnknown; + case LinphoneReasonBadCredentials: + return SalReasonForbidden; + case LinphoneReasonDeclined: + return SalReasonDeclined; + case LinphoneReasonNotFound: + return SalReasonNotFound; + case LinphoneReasonNotAnswered: + return SalReasonTemporarilyUnavailable; + case LinphoneReasonBusy: + return SalReasonBusy; + case LinphoneReasonMedia: + return SalReasonMedia; + case LinphoneReasonIOError: + return SalReasonServiceUnavailable; + case LinphoneReasonDoNotDisturb: + return SalReasonDoNotDisturb; + case LinphoneReasonUnauthorized: + return SalReasonUnauthorized; + case LinphoneReasonNotAcceptable: + return SalReasonNotAcceptable; + } + return SalReasonUnknown; +} + +LinphoneReason linphone_reason_from_sal(SalReason r){ + LinphoneReason ret=LinphoneReasonNone; + switch(r){ + case SalReasonUnknown: + ret=LinphoneReasonNone; + break; + case SalReasonBusy: + ret=LinphoneReasonBusy; + break; + case SalReasonDeclined: + ret=LinphoneReasonDeclined; + break; + case SalReasonDoNotDisturb: + ret=LinphoneReasonDoNotDisturb; + break; + case SalReasonForbidden: + ret=LinphoneReasonBadCredentials; + break; + case SalReasonMedia: + ret=LinphoneReasonMedia; + break; + case SalReasonNotFound: + ret=LinphoneReasonNotFound; + break; + case SalReasonRedirect: + ret=LinphoneReasonNone; + break; + case SalReasonTemporarilyUnavailable: + ret=LinphoneReasonNone; + break; + case SalReasonServiceUnavailable: + ret=LinphoneReasonIOError; + break; + case SalReasonRequestPending: + ret=LinphoneReasonNone; + break; + case SalReasonUnauthorized: + ret=LinphoneReasonUnauthorized; + break; + case SalReasonNotAcceptable: + ret=LinphoneReasonNotAcceptable; + break; + } + return ret; +} + +/** + * 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. + * @ingroup media_parameters +**/ +void linphone_core_set_video_display_filter(LinphoneCore *lc, const char *filter_name){ + lp_config_set_string(lc->config,"video","displaytype",filter_name); +} + +/** + * Get the name of the mediastreamer2 filter used for rendering video. + * @ingroup media_parameters +**/ +const char *linphone_core_get_video_display_filter(LinphoneCore *lc){ + return lp_config_get_string(lc->config,"video","displaytype",NULL); +} + + + diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 9823c24a6..42d856310 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "sal.h" +#include "sal/sal.h" #include "offeranswer.h" #include "private.h" @@ -40,7 +40,8 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload for (elem=l;elem!=NULL;elem=elem->next){ pt=(PayloadType*)elem->data; /* the compare between G729 and G729A is for some stupid uncompliant phone*/ - if ( (strcasecmp(pt->mime_type,refpt->mime_type)==0 || + if ( pt->mime_type && refpt->mime_type && + (strcasecmp(pt->mime_type,refpt->mime_type)==0 || (strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 )) && pt->clock_rate==refpt->clock_rate){ candidate=pt; diff --git a/coreapi/presence.c b/coreapi/presence.c index ca6357258..e4cd069b9 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1,6 +1,6 @@ /* linphone -Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) +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 @@ -19,21 +19,1514 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" +#include "lpconfig.h" +#include "linphonepresence.h" + +#include +#include +#include +#include + + +#define XMLPARSING_BUFFER_LEN 2048 +#define MAX_XPATH_LENGTH 256 + extern const char *__policy_enum_to_str(LinphoneSubscribePolicy pol); + +struct _LinphonePresenceNote { + void *user_data; + int refcnt; + char *lang; + char *content; +}; + +struct _LinphonePresenceService { + void *user_data; + int refcnt; + char *id; + LinphonePresenceBasicStatus status; + char *contact; + MSList *notes; /**< A list of _LinphonePresenceNote structures. */ + time_t timestamp; +}; + +struct _LinphonePresenceActivity { + void *user_data; + int refcnt; + LinphonePresenceActivityType type; + char *description; +}; + +struct _LinphonePresencePerson { + void *user_data; + int refcnt; + char *id; + MSList *activities; /**< A list of _LinphonePresenceActivity structures. */ + MSList *activities_notes; /**< A list of _LinphonePresenceNote structures. */ + MSList *notes; /**< A list of _LinphonePresenceNote structures. */ + time_t timestamp; +}; + +/** + * Represents the presence model as defined in RFC 4479 and RFC 4480. + * This model is not complete. For example, it does not handle devices. + */ +struct _LinphonePresenceModel { + void *user_data; + int refcnt; + MSList *services; /**< A list of _LinphonePresenceService structures. Also named tuples in the RFC. */ + MSList *persons; /**< A list of _LinphonePresencePerson structures. */ + 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"; + + +/***************************************************************************** + * 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) { + char id[7]; + int i; + + for (i = 0; i < 6; i++) { + id[i] = presence_id_valid_characters[random() % sizeof(presence_id_valid_characters)]; + } + id[6] = '\0'; + + return ms_strdup(id); +} + +static const char * presence_basic_status_to_string(LinphonePresenceBasicStatus basic_status) { + switch (basic_status) { + case LinphonePresenceBasicStatusOpen: + return "open"; + case LinphonePresenceBasicStatusClosed: + default: + return "closed"; + } +} + +static void presence_note_delete(LinphonePresenceNote *note) { + ms_free(note->content); + if (note->lang != NULL) { + ms_free(note->lang); + } + ms_free(note); +} + +static LinphonePresenceService * presence_service_new(const char *id, LinphonePresenceBasicStatus status) { + LinphonePresenceService *service = ms_new0(LinphonePresenceService, 1); + service->refcnt = 1; + if (id != NULL) { + service->id = ms_strdup(id); + } + service->status = status; + service->timestamp = time(NULL); + return service; +} + +static void presence_service_delete(LinphonePresenceService *service) { + if (service->id != NULL) { + ms_free(service->id); + } + if (service->contact != NULL) { + ms_free(service->contact); + } + ms_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(service->notes); + ms_free(service); +}; + +static void presence_service_set_timestamp(LinphonePresenceService *service, time_t timestamp) { + service->timestamp = timestamp; +} + +static void presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) { + service->notes = ms_list_append(service->notes, note); +} + +static void presence_activity_delete(LinphonePresenceActivity *activity) { + if (activity->description != NULL) { + ms_free(activity->description); + } + ms_free(activity); +} + +static time_t parse_timestamp(const char *timestamp) { + struct tm ret; + time_t seconds; + + memset(&ret, 0, sizeof(ret)); + sscanf(timestamp, "%d-%d-%dT%d:%d:%d", + &ret.tm_year, &ret.tm_mon, &ret.tm_mday, &ret.tm_hour, &ret.tm_min, &ret.tm_sec); + ret.tm_mon--; + ret.tm_year -= 1900; + ret.tm_isdst = 0; + seconds = mktime(&ret); + if (seconds == (time_t)-1) { + ms_error("mktime() failed: %s", strerror(errno)); + return (time_t)-1; + } + return seconds - timezone; +} + +static char * timestamp_to_string(time_t timestamp) { + char timestamp_str[22]; + struct tm *ret; +#ifndef WIN32 + struct tm gmt; + ret = gmtime_r(×tamp,&gmt); +#else + ret = gmtime(×tamp); +#endif + snprintf(timestamp_str, sizeof(timestamp_str), "%4d-%02d-%02dT%02d:%02d:%02dZ", + ret->tm_year + 1900, ret->tm_mon + 1, ret->tm_mday, ret->tm_hour, ret->tm_min, ret->tm_sec); + return ms_strdup(timestamp_str); +} + +static LinphonePresencePerson * presence_person_new(const char *id, time_t timestamp) { + LinphonePresencePerson *person = ms_new0(LinphonePresencePerson, 1); + person->refcnt = 1; + if (id != NULL) { + person->id = ms_strdup(id); + } + if (person->timestamp == ((time_t)-1)) + person->timestamp = time(NULL); + else + person->timestamp = timestamp; + return person; +} + +static void presence_person_delete(LinphonePresencePerson *person) { + if (person->id != NULL) { + ms_free(person->id); + } + ms_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref); + ms_list_free(person->activities); + ms_list_for_each(person->activities_notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(person->activities_notes); + ms_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(person->notes); + ms_free(person); +} + +static void presence_person_add_activities_note(LinphonePresencePerson *person, LinphonePresenceNote *note) { + person->activities_notes = ms_list_append(person->activities_notes, note); +} + +static void presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note) { + person->notes = ms_list_append(person->notes, note); +} + +static void presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) { + model->persons = ms_list_append(model->persons, person); +} + +static void presence_model_add_note(LinphonePresenceModel *model, LinphonePresenceNote *note) { + model->notes = ms_list_append(model->notes, note); +} + +static void presence_model_find_open_basic_status(LinphonePresenceService *service, LinphonePresenceBasicStatus *status) { + if (service->status == LinphonePresenceBasicStatusOpen) { + *status = LinphonePresenceBasicStatusOpen; + } +} + +static void presence_model_delete(LinphonePresenceModel *model) { + if (model == NULL) return; + + ms_list_for_each(model->services, (MSIterateFunc)linphone_presence_service_unref); + ms_list_free(model->services); + ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_unref); + ms_list_free(model->persons); + ms_list_for_each(model->notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(model->notes); + ms_free(model); +} + + + +/***************************************************************************** + * HELPER FUNCTIONS TO EASE ACCESS IN MOST SIMPLER CASES * + ****************************************************************************/ + +LinphonePresenceModel * linphone_presence_model_new_with_activity(LinphonePresenceActivityType acttype, const char *description) { + LinphonePresenceModel *model = linphone_presence_model_new(); + if (model != NULL) { + linphone_presence_model_set_activity(model, acttype, description); + } + return model; +} + +LinphonePresenceModel * linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivityType acttype, const char *description, const char *note, const char *lang) { + LinphonePresenceModel *model = linphone_presence_model_new(); + if (model != NULL) { + linphone_presence_model_set_activity(model, acttype, description); + linphone_presence_model_add_note(model, note, lang); + } + return model; +} + +/* Suppose that if at least one service is open, then the model is open. */ +LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const LinphonePresenceModel *model) { + LinphonePresenceBasicStatus status = LinphonePresenceBasicStatusClosed; + if (model != NULL) { + ms_list_for_each2(model->services, (MSIterate2Func)presence_model_find_open_basic_status, &status); + } + return status; +} + +int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) { + LinphonePresenceService *service; + + if (model == NULL) return -1; + + linphone_presence_model_clear_services(model); + service = linphone_presence_service_new(NULL, basic_status, NULL); + if (service == NULL) return -1; + + if (linphone_presence_model_add_service(model, service) < 0) return -1; + return 0; +} + +static void presence_service_find_newer_timestamp(LinphonePresenceService *service, time_t *timestamp) { + if (service->timestamp > *timestamp) + *timestamp = service->timestamp; +} + +static void presence_person_find_newer_timestamp(LinphonePresencePerson *person, time_t *timestamp) { + if (person->timestamp > *timestamp) + *timestamp = person->timestamp; +} + +time_t linphone_presence_model_get_timestamp(const LinphonePresenceModel *model) { + time_t timestamp = (time_t)-1; + + if (model == NULL) + return timestamp; + + ms_list_for_each2(model->services, (MSIterate2Func)presence_service_find_newer_timestamp, ×tamp); + ms_list_for_each2(model->persons, (MSIterate2Func)presence_person_find_newer_timestamp, ×tamp); + + return timestamp; +} + +static void presence_model_find_contact(LinphonePresenceService *service, char **contact) { + if ((service->contact != NULL) && (*contact == NULL)) + *contact = service->contact; +} + +char * linphone_presence_model_get_contact(const LinphonePresenceModel *model) { + char *contact = NULL; + ms_list_for_each2(model->services, (MSIterate2Func)presence_model_find_contact, &contact); + if (contact == NULL) return NULL; + return ms_strdup(contact); +} + +int linphone_presence_model_set_contact(LinphonePresenceModel *model, const char *contact) { + LinphonePresenceService *service; + + if (model == NULL) return -1; + + service = linphone_presence_model_get_nth_service(model, 0); + if (service == NULL) { + service = linphone_presence_service_new(NULL, LinphonePresenceBasicStatusClosed, NULL); + if (service == NULL) return -1; + linphone_presence_model_add_service(model, service); + } + return linphone_presence_service_set_contact(service, contact); +} + +static void presence_model_count_activities(const LinphonePresencePerson *person, unsigned int *nb) { + *nb += ms_list_size(person->activities); +} + +struct _get_activity_st { + unsigned int requested_idx; + unsigned int current_idx; + LinphonePresenceActivity *activity; +}; + +static void presence_model_get_activity(const LinphonePresencePerson *person, struct _get_activity_st *st) { + unsigned int size = ms_list_size(person->activities); + if (st->requested_idx < (st->current_idx + size)) { + st->activity = (LinphonePresenceActivity *)ms_list_nth_data(person->activities, st->requested_idx - st->current_idx); + } else { + st->current_idx += size; + } +} + +LinphonePresenceActivity * linphone_presence_model_get_activity(const LinphonePresenceModel *model) { + return linphone_presence_model_get_nth_activity(model, 0); +} + +int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) { + LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusOpen; + LinphonePresenceActivity *activity; + + if (model == NULL) return -1; + + switch (acttype) { + case LinphonePresenceActivityAppointment: + case LinphonePresenceActivityBusy: + case LinphonePresenceActivityMeeting: + case LinphonePresenceActivityPermanentAbsence: + case LinphonePresenceActivityOffline: + case LinphonePresenceActivityWorship: + basic_status = LinphonePresenceBasicStatusClosed; + break; + default: + basic_status = LinphonePresenceBasicStatusOpen; + break; + } + if (linphone_presence_model_set_basic_status(model, basic_status) < 0) return -1; + linphone_presence_model_clear_activities(model); + activity = linphone_presence_activity_new(acttype, description); + if (activity == NULL) return -1; + return linphone_presence_model_add_activity(model, activity); + +} + +unsigned int linphone_presence_model_get_nb_activities(const LinphonePresenceModel *model) { + unsigned int nb = 0; + ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_count_activities, &nb); + return nb; +} + +LinphonePresenceActivity * linphone_presence_model_get_nth_activity(const LinphonePresenceModel *model, unsigned int idx) { + struct _get_activity_st st; + + if ((model == NULL) || (idx >= linphone_presence_model_get_nb_activities(model))) + return NULL; + + memset(&st, 0, sizeof(st)); + st.requested_idx = idx; + ms_list_for_each2(model->persons, (MSIterate2Func)presence_model_get_activity, &st); + + return st.activity; +} + +int linphone_presence_model_add_activity(LinphonePresenceModel *model, LinphonePresenceActivity *activity) { + char *id = NULL; + LinphonePresencePerson *person = NULL; + + if ((model == NULL) || (activity == NULL)) return -1; + + if (ms_list_size(model->persons) == 0) { + /* There is no person in the presence model, add one. */ + id = generate_presence_id(); + person = presence_person_new(id, time(NULL)); + if (id != NULL) ms_free(id); + if (person == NULL) + return -1; + + presence_model_add_person(model, person); + } else { + /* Add the activity to the first person in the model. */ + person = (LinphonePresencePerson *)ms_list_nth_data(model->persons, 0); + } + + linphone_presence_person_add_activity(person, activity); + return 0; +} + +int linphone_presence_model_clear_activities(LinphonePresenceModel *model) { + if (model == NULL) return -1; + + ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_clear_activities); + return 0; +} + +struct _find_note_st { + const char *lang; + LinphonePresenceNote *note; +}; + +static LinphonePresenceNote * find_presence_note_in_list(MSList *list, const char *lang) { + int nb; + int i; + + nb = ms_list_size(list); + for (i = 0; i < nb; i++) { + LinphonePresenceNote *note = (LinphonePresenceNote *)ms_list_nth_data(list, i); + if (lang == NULL) { + if (note->lang == NULL) { + return note; + } + } else { + if ((note->lang != NULL) && (strcmp(lang, note->lang) == 0)) { + return note; + } + } + } + + return NULL; +} + +static void find_presence_person_note(LinphonePresencePerson *person, struct _find_note_st *st) { + /* First look for the note in the activities notes... */ + st->note = find_presence_note_in_list(person->activities_notes, st->lang); + if (st->note != NULL) return; + + /* ... then look in the person notes. */ + st->note = find_presence_note_in_list(person->notes, st->lang); +} + +static void find_presence_service_note(LinphonePresenceService *service, struct _find_note_st *st) { + st->note = find_presence_note_in_list(service->notes, st->lang); +} + +static LinphonePresenceNote * get_first_presence_note_in_list(MSList *list) { + return (LinphonePresenceNote *)ms_list_nth_data(list, 0); +} + +static void get_first_presence_person_note(LinphonePresencePerson *person, struct _find_note_st *st) { + st->note = get_first_presence_note_in_list(person->activities_notes); + if (st->note != NULL) return; + st->note = get_first_presence_note_in_list(person->notes); +} + +static void get_first_presence_service_note(LinphonePresenceService *service, struct _find_note_st *st) { + st->note = get_first_presence_note_in_list(service->notes); +} + +LinphonePresenceNote * linphone_presence_model_get_note(const LinphonePresenceModel *model, const char *lang) { + struct _find_note_st st; + + if (model == NULL) return NULL; + + st.note = NULL; + if (lang != NULL) { + /* First try to find a note in the specified language exactly. */ + st.lang = lang; + ms_list_for_each2(model->persons, (MSIterate2Func)find_presence_person_note, &st); + if (st.note == NULL) { + ms_list_for_each2(model->services, (MSIterate2Func)find_presence_service_note, &st); + } + if (st.note == NULL) { + st.note = find_presence_note_in_list(model->notes, lang); + } + } + + if (st.note == NULL) { + /* No notes in the specified language has been found, try to find one without language. */ + st.lang = NULL; + ms_list_for_each2(model->persons, (MSIterate2Func)find_presence_person_note, &st); + if (st.note == NULL) { + ms_list_for_each2(model->services, (MSIterate2Func)find_presence_service_note, &st); + } + if (st.note == NULL) { + st.note = find_presence_note_in_list(model->notes, NULL); + } + } + + if (st.note == NULL) { + /* Still no result, so get the first note even if it is not in the specified language. */ + ms_list_for_each2(model->persons, (MSIterate2Func)get_first_presence_person_note, &st); + if (st.note == NULL) { + ms_list_for_each2(model->services, (MSIterate2Func)get_first_presence_service_note, &st); + } + if (st.note == NULL) { + st.note = get_first_presence_note_in_list(model->notes); + } + } + + return st.note; +} + +int linphone_presence_model_add_note(LinphonePresenceModel *model, const char *note_content, const char *lang) { + LinphonePresenceService *service; + LinphonePresenceNote *note; + + if ((model == NULL) || (note_content == NULL)) + return -1; + + /* Will put the note in the first service. */ + service = ms_list_nth_data(model->services, 0); + if (service == NULL) { + /* If no service exists, create one. */ + service = presence_service_new(generate_presence_id(), LinphonePresenceBasicStatusClosed); + } + if (service == NULL) + return -1; + + /* Search for an existing note in the specified language. */ + note = find_presence_note_in_list(service->notes, lang); + if (note == NULL) { + note = linphone_presence_note_new(note_content, lang); + } else { + linphone_presence_note_set_content(note, note_content); + } + if (note == NULL) + return -1; + + presence_service_add_note(service, note); + + return 0; +} + +static void clear_presence_person_notes(LinphonePresencePerson *person) { + ms_list_for_each(person->activities_notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(person->activities_notes); + person->activities_notes = NULL; + ms_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(person->notes); + person->notes = NULL; +} + +static void clear_presence_service_notes(LinphonePresenceService *service) { + ms_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(service->notes); + service->notes = NULL; +} + +int linphone_presence_model_clear_notes(LinphonePresenceModel *model) { + if (model == NULL) + return -1; + + ms_list_for_each(model->persons, (MSIterateFunc)clear_presence_person_notes); + ms_list_for_each(model->services, (MSIterateFunc)clear_presence_service_notes); + ms_list_for_each(model->notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(model->notes); + model->notes = NULL; + + return 0; +} + +/***************************************************************************** + * PRESENCE MODEL FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +LinphonePresenceModel * linphone_presence_model_new(void) { + LinphonePresenceModel *model = ms_new0(LinphonePresenceModel, 1); + model->refcnt = 1; + return model; +} + +unsigned int linphone_presence_model_get_nb_services(const LinphonePresenceModel *model) { + return ms_list_size(model->services); +} + +LinphonePresenceService * linphone_presence_model_get_nth_service(const LinphonePresenceModel *model, unsigned int idx) { + if ((model == NULL) || (idx >= linphone_presence_model_get_nb_services(model))) + return NULL; + + return (LinphonePresenceService *)ms_list_nth_data(model->services, idx); +} + +int linphone_presence_model_add_service(LinphonePresenceModel *model, LinphonePresenceService *service) { + if ((model == NULL) || (service == NULL)) return -1; + model->services = ms_list_append(model->services, linphone_presence_service_ref(service)); + return 0; +} + +int linphone_presence_model_clear_services(LinphonePresenceModel *model) { + if (model == NULL) return -1; + + ms_list_for_each(model->services, (MSIterateFunc)linphone_presence_service_unref); + ms_list_free(model->services); + model->services = NULL; + return 0; +} + +unsigned int linphone_presence_model_get_nb_persons(const LinphonePresenceModel *model) { + return ms_list_size(model->persons); +} + +LinphonePresencePerson * linphone_presence_model_get_nth_person(const LinphonePresenceModel *model, unsigned int idx) { + if ((model == NULL) || (idx >= linphone_presence_model_get_nb_persons(model))) + return NULL; + + return (LinphonePresencePerson *)ms_list_nth_data(model->persons, idx); +} + +int linphone_presence_model_add_person(LinphonePresenceModel *model, LinphonePresencePerson *person) { + if ((model == NULL) || (person == NULL)) return -1; + model->persons = ms_list_append(model->persons, linphone_presence_person_ref(person)); + return 0; +} + +int linphone_presence_model_clear_persons(LinphonePresenceModel *model) { + if (model == NULL) return -1; + + ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_unref); + ms_list_free(model->persons); + model->persons = NULL; + return 0; +} + + + +/***************************************************************************** + * PRESENCE SERVICE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus basic_status, const char *contact) { + LinphonePresenceService *service; + char *service_id; + if (id == NULL) + service_id = generate_presence_id(); + else + service_id = ms_strdup(id); + service = presence_service_new(service_id, basic_status); + linphone_presence_service_set_contact(service, contact); + if (service_id != NULL) + ms_free(service_id); + return service; +} + +char * linphone_presence_service_get_id(const LinphonePresenceService *service) { + if (service == NULL) return NULL; + return ms_strdup(service->id); +} + +int linphone_presence_service_set_id(LinphonePresenceService *service, const char *id) { + if (service == NULL) return -1; + if (service->id != NULL) + ms_free(service->id); + if (id == NULL) + service->id = generate_presence_id(); + else + service->id = ms_strdup(id); + return 0; +} + +LinphonePresenceBasicStatus linphone_presence_service_get_basic_status(const LinphonePresenceService *service) { + if (service == NULL) return LinphonePresenceBasicStatusClosed; + return service->status; +} + +int linphone_presence_service_set_basic_status(LinphonePresenceService *service, LinphonePresenceBasicStatus basic_status) { + if (service == NULL) return -1; + service->status = basic_status; + return 0; +} + +char * linphone_presence_service_get_contact(const LinphonePresenceService *service) { + if (service->contact == NULL) return NULL; + return ms_strdup(service->contact); +} + +int linphone_presence_service_set_contact(LinphonePresenceService *service, const char *contact) { + if (service == NULL) return -1; + if (service->contact != NULL) + ms_free(service->contact); + if (contact != NULL) + service->contact = ms_strdup(contact); + else + service->contact = NULL; + return 0; +} + +unsigned int linphone_presence_service_get_nb_notes(const LinphonePresenceService *service) { + return ms_list_size(service->notes); +} + +LinphonePresenceNote * linphone_presence_service_get_nth_note(const LinphonePresenceService *service, unsigned int idx) { + if ((service == NULL) || (idx >= linphone_presence_service_get_nb_notes(service))) + return NULL; + + return (LinphonePresenceNote *)ms_list_nth_data(service->notes, idx); +} + +int linphone_presence_service_add_note(LinphonePresenceService *service, LinphonePresenceNote *note) { + if ((service == NULL) || (note == NULL)) return -1; + service->notes = ms_list_append(service->notes, linphone_presence_note_ref(note)); + return 0; +} + +int linphone_presence_service_clear_notes(LinphonePresenceService *service) { + if (service == NULL) return -1; + + ms_list_for_each(service->notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(service->notes); + service->notes = NULL; + return 0; +} + + + +/***************************************************************************** + * PRESENCE PERSON FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +LinphonePresencePerson * linphone_presence_person_new(const char *id) { + return presence_person_new(id, time(NULL)); +} + +char * linphone_presence_person_get_id(const LinphonePresencePerson *person) { + if (person == NULL) return NULL; + return ms_strdup(person->id); +} + +int linphone_presence_person_set_id(LinphonePresencePerson *person, const char *id) { + if (person == NULL) return -1; + if (person->id != NULL) + ms_free(person->id); + if (id == NULL) + person->id = generate_presence_id(); + else + person->id = ms_strdup(id); + return 0; +} + +unsigned int linphone_presence_person_get_nb_activities(const LinphonePresencePerson *person) { + if (person == NULL) return 0; + return ms_list_size(person->activities); +} + +LinphonePresenceActivity * linphone_presence_person_get_nth_activity(const LinphonePresencePerson *person, unsigned int idx) { + if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities(person))) + return NULL; + return (LinphonePresenceActivity *)ms_list_nth_data(person->activities, idx); +} + +int linphone_presence_person_add_activity(LinphonePresencePerson *person, LinphonePresenceActivity *activity) { + if ((person == NULL) || (activity == NULL)) return -1; + person->activities = ms_list_append(person->activities, linphone_presence_activity_ref(activity)); + return 0; +} + +int linphone_presence_person_clear_activities(LinphonePresencePerson *person) { + if (person == NULL) return -1; + ms_list_for_each(person->activities, (MSIterateFunc)linphone_presence_activity_unref); + ms_list_free(person->activities); + person->activities = NULL; + return 0; +} + +unsigned int linphone_presence_person_get_nb_notes(const LinphonePresencePerson *person) { + if (person == NULL) return 0; + return ms_list_size(person->notes); +} + +LinphonePresenceNote * linphone_presence_person_get_nth_note(const LinphonePresencePerson *person, unsigned int idx) { + if ((person == NULL) || (idx >= linphone_presence_person_get_nb_notes(person))) + return NULL; + return (LinphonePresenceNote *)ms_list_nth_data(person->notes, idx); +} + +int linphone_presence_person_add_note(LinphonePresencePerson *person, LinphonePresenceNote *note) { + if ((person == NULL) || (note == NULL)) return -1; + person->notes = ms_list_append(person->notes, linphone_presence_note_ref(note)); + return 0; +} + +int linphone_presence_person_clear_notes(LinphonePresencePerson *person) { + if (person == NULL) return -1; + ms_list_for_each(person->notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(person->notes); + person->notes = NULL; + return 0; +} + +unsigned int linphone_presence_person_get_nb_activities_notes(const LinphonePresencePerson *person) { + if (person == NULL) return 0; + return ms_list_size(person->activities_notes); +} + +LinphonePresenceNote * linphone_presence_person_get_nth_activities_note(const LinphonePresencePerson *person, unsigned int idx) { + if ((person == NULL) || (idx >= linphone_presence_person_get_nb_activities_notes(person))) + return NULL; + return (LinphonePresenceNote *)ms_list_nth_data(person->activities_notes, idx); +} + +int linphone_presence_person_add_activities_note(LinphonePresencePerson *person, LinphonePresenceNote *note) { + if ((person == NULL) || (note == NULL)) return -1; + person->notes = ms_list_append(person->activities_notes, linphone_presence_note_ref(note)); + return 0; +} + +int linphone_presence_person_clear_activities_notes(LinphonePresencePerson *person) { + if (person == NULL) return -1; + ms_list_for_each(person->activities_notes, (MSIterateFunc)linphone_presence_note_unref); + ms_list_free(person->activities_notes); + person->activities_notes = NULL; + return 0; +} + + +/***************************************************************************** + * PRESENCE ACTIVITY FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +struct _presence_activity_name_map { + const char *name; + LinphonePresenceActivityType type; +}; + +static struct _presence_activity_name_map activity_map[] = { + { "appointment", LinphonePresenceActivityAppointment }, + { "away", LinphonePresenceActivityAway }, + { "breakfast", LinphonePresenceActivityBreakfast }, + { "busy", LinphonePresenceActivityBusy }, + { "dinner", LinphonePresenceActivityDinner }, + { "holiday", LinphonePresenceActivityHoliday }, + { "in-transit", LinphonePresenceActivityInTransit }, + { "looking-for-work", LinphonePresenceActivityLookingForWork }, + { "lunch", LinphonePresenceActivityLunch }, + { "meal", LinphonePresenceActivityMeal }, + { "meeting", LinphonePresenceActivityMeeting }, + { "on-the-phone", LinphonePresenceActivityOnThePhone }, + { "other", LinphonePresenceActivityOther }, + { "performance", LinphonePresenceActivityPerformance }, + { "permanent-absence", LinphonePresenceActivityPermanentAbsence }, + { "playing", LinphonePresenceActivityPlaying }, + { "presentation", LinphonePresenceActivityPresentation }, + { "shopping", LinphonePresenceActivityShopping }, + { "sleeping", LinphonePresenceActivitySleeping }, + { "spectator", LinphonePresenceActivitySpectator }, + { "steering", LinphonePresenceActivitySteering }, + { "travel", LinphonePresenceActivityTravel }, + { "tv", LinphonePresenceActivityTV }, + { "unknown", LinphonePresenceActivityUnknown }, + { "vacation", LinphonePresenceActivityVacation }, + { "working", LinphonePresenceActivityWorking }, + { "worship", LinphonePresenceActivityWorship } +}; + +static int activity_name_to_presence_activity_type(const char *name, LinphonePresenceActivityType *acttype) { + unsigned int i; + for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) { + if (strcmp(name, activity_map[i].name) == 0) { + *acttype = activity_map[i].type; + return 0; + } + } + return -1; +} + +static const char * presence_activity_type_to_string(LinphonePresenceActivityType acttype) { + unsigned int i; + for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) { + if (acttype == activity_map[i].type) { + return activity_map[i].name; + } + } + return NULL; +} + +LinphonePresenceActivity * linphone_presence_activity_new(LinphonePresenceActivityType acttype, const char *description) { + LinphonePresenceActivity *act = ms_new0(LinphonePresenceActivity, 1); + act->refcnt = 1; + act->type = acttype; + if (description != NULL) { + act->description = ms_strdup(description); + } + return act; +} + +char * linphone_presence_activity_to_string(const LinphonePresenceActivity *activity) { + LinphonePresenceActivityType acttype = linphone_presence_activity_get_type(activity); + const char *description = linphone_presence_activity_get_description(activity); + const char *acttype_str; + + if (acttype == LinphonePresenceActivityOffline) + acttype_str = "offline"; + else if (acttype == LinphonePresenceActivityOnline) + acttype_str = "online"; + else + acttype_str = presence_activity_type_to_string(acttype); + + return ms_strdup_printf("%s%s%s", acttype_str, + (description == NULL) ? "" : ": ", + (description == NULL) ? "" : description); +} + +LinphonePresenceActivityType linphone_presence_activity_get_type(const LinphonePresenceActivity *activity) { + if (activity == NULL) + return LinphonePresenceActivityOffline; + return activity->type; +} + +int linphone_presence_activity_set_type(LinphonePresenceActivity *activity, LinphonePresenceActivityType acttype) { + if (activity == NULL) return -1; + activity->type = acttype; + return 0; +} + +const char * linphone_presence_activity_get_description(const LinphonePresenceActivity *activity) { + if (activity == NULL) + return NULL; + return activity->description; +} + +int linphone_presence_activity_set_description(LinphonePresenceActivity *activity, const char *description) { + if (activity == NULL) return -1; + if (activity->description != NULL) + ms_free(activity->description); + if (description != NULL) + activity->description = ms_strdup(description); + else + activity->description = NULL; + return 0; +} + + + +/***************************************************************************** + * PRESENCE NOTE FUNCTIONS TO GET ACCESS TO ALL FUNCTIONALITIES * + ****************************************************************************/ + +LinphonePresenceNote * linphone_presence_note_new(const char *content, const char *lang) { + LinphonePresenceNote *note; + + if (content == NULL) return NULL; + note = ms_new0(LinphonePresenceNote, 1); + note->refcnt = 1; + note->content = ms_strdup(content); + if (lang != NULL) { + note->lang = ms_strdup(lang); + } + return note; +} + +const char * linphone_presence_note_get_content(const LinphonePresenceNote *note) { + if (note == NULL) + return NULL; + return note->content; +} + +int linphone_presence_note_set_content(LinphonePresenceNote *note, const char *content) { + if (content == NULL) return -1; + if (note->content != NULL) { + ms_free(note->content); + } + note->content = ms_strdup(content); + return 0; +} + +const char * linphone_presence_note_get_lang(const LinphonePresenceNote *note) { + if (note == NULL) + return NULL; + return note->lang; +} + +int linphone_presence_note_set_lang(LinphonePresenceNote *note, const char *lang) { + if (note->lang != NULL) { + ms_free(note->lang); + note->lang = NULL; + } + if (lang != NULL) { + note->lang = ms_strdup(lang); + } + return 0; +} + + + +/***************************************************************************** + * PRESENCE INTERNAL FUNCTIONS FOR WRAPPERS IN OTHER PROGRAMMING LANGUAGES * + ****************************************************************************/ + +LinphonePresenceModel * linphone_presence_model_ref(LinphonePresenceModel *model) { + model->refcnt++; + return model; +} + +LinphonePresenceModel * linphone_presence_model_unref(LinphonePresenceModel *model) { + model->refcnt--; + if (model->refcnt == 0) { + presence_model_delete(model); + return NULL; + } + return model; +} + +void linphone_presence_model_set_user_data(LinphonePresenceModel *model, void *user_data) { + model->user_data = user_data; +} + +void * linphone_presence_model_get_user_data(LinphonePresenceModel *model) { + return model->user_data; +} + +LinphonePresenceService * linphone_presence_service_ref(LinphonePresenceService *service) { + service->refcnt++; + return service; +} + +LinphonePresenceService * linphone_presence_service_unref(LinphonePresenceService *service) { + service->refcnt--; + if (service->refcnt == 0) { + presence_service_delete(service); + return NULL; + } + return service; +} + +void linphone_presence_service_set_user_data(LinphonePresenceService *service, void *user_data) { + service->user_data = user_data; +} + +void * linphone_presence_service_get_user_data(LinphonePresenceService *service) { + return service->user_data; +} + +LinphonePresencePerson * linphone_presence_person_ref(LinphonePresencePerson *person) { + person->refcnt++; + return person; +} + +LinphonePresencePerson * linphone_presence_person_unref(LinphonePresencePerson *person) { + person->refcnt--; + if (person->refcnt == 0) { + presence_person_delete(person); + return NULL; + } + return person; +} + +void linphone_presence_person_set_user_data(LinphonePresencePerson *person, void *user_data) { + person->user_data = user_data; +} + +void * linphone_presence_person_get_user_data(LinphonePresencePerson *person) { + return person->user_data; +} + +LinphonePresenceActivity * linphone_presence_activity_ref(LinphonePresenceActivity *activity) { + activity->refcnt++; + return activity; +} + +LinphonePresenceActivity * linphone_presence_activity_unref(LinphonePresenceActivity *activity) { + activity->refcnt--; + if (activity->refcnt == 0) { + presence_activity_delete(activity); + return NULL; + } + return activity; +} + +void linphone_presence_activity_set_user_data(LinphonePresenceActivity *activity, void *user_data) { + activity->user_data = user_data; +} + +void * linphone_presence_activity_get_user_data(LinphonePresenceActivity *activity) { + return activity->user_data; +} + +LinphonePresenceNote * linphone_presence_note_ref(LinphonePresenceNote *note) { + note->refcnt++; + return note; +} + +LinphonePresenceNote * linphone_presence_note_unref(LinphonePresenceNote *note) { + note->refcnt--; + if (note->refcnt == 0) { + presence_note_delete(note); + return NULL; + } + return note; +} + +void linphone_presence_note_set_user_data(LinphonePresenceNote *note, void *user_data) { + note->user_data = user_data; +} + +void * linphone_presence_note_get_user_data(LinphonePresenceNote *note) { + return note->user_data; +} + + + +/***************************************************************************** + * 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) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr note_object; + LinphonePresenceNote *note; + const char *note_str; + const char *lang; + 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); + 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); + 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); + + 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 (note_object != NULL) xmlXPathFreeObject(note_object); + + return 0; +} + +static int process_pidf_xml_presence_services(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr service_object; + LinphonePresenceService *service; + const char *basic_status_str; + const char *service_id_str; + const char *timestamp_str; + const char *contact_str; + LinphonePresenceBasicStatus basic_status; + int i; + + service_object = 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); + if (basic_status_str == NULL) + continue; + + if (strcmp(basic_status_str, "open") == 0) { + basic_status = LinphonePresenceBasicStatusOpen; + } else if (strcmp(basic_status_str, "closed") == 0) { + basic_status = LinphonePresenceBasicStatusClosed; + } else { + /* Invalid value for basic status. */ + 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); + + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:contact", service_prefix, i); + contact_str = 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 = 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); + } + if (contact_str != NULL) { + linphone_presence_service_set_contact(service, contact_str); + 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); + } + } + if (service_object != NULL) xmlXPathFreeObject(service_object); + + return 0; +} + +static bool_t is_valid_activity_name(const char *name) { + unsigned int i; + for (i = 0; i < (sizeof(activity_map) / sizeof(activity_map[0])); i++) { + if (strcmp(name, activity_map[i].name) == 0) { + return TRUE; + } + } + return FALSE; +} + +static int process_pidf_xml_presence_person_activities(xmlparsing_context_t *xml_ctx, LinphonePresencePerson *person, unsigned int person_idx) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr activities_nodes_object; + xmlXPathObjectPtr activities_object; + xmlNodePtr activity_node; + LinphonePresenceActivity *activity; + const char *description; + int i, j; + 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); + 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); + if ((activities_object != NULL) && (activities_object->nodesetval != NULL)) { + for (j = 0; j < activities_object->nodesetval->nodeNr; j++) { + activity_node = activities_object->nodesetval->nodeTab[j]; + if ((activity_node->name != NULL) && (is_valid_activity_name((const char *)activity_node->name) == TRUE)) { + LinphonePresenceActivityType acttype; + description = (const char *)xmlNodeGetContent(activity_node); + if ((description != NULL) && (description[0] == '\0')) { + 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 (activities_object != NULL) xmlXPathFreeObject(activities_object); + if (err < 0) break; + } + } + if (activities_nodes_object != NULL) xmlXPathFreeObject(activities_nodes_object); + + return err; +} + +static int process_pidf_xml_presence_person_notes(xmlparsing_context_t *xml_ctx, LinphonePresencePerson *person, unsigned int person_idx) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr note_object; + LinphonePresenceNote *note; + const char *note_str; + const char *lang; + 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); + 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); + 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); + + 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 (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); + 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); + 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); + + 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 (note_object != NULL) xmlXPathFreeObject(note_object); + + return 0; +} + +static int process_pidf_xml_presence_persons(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr person_object; + LinphonePresencePerson *person; + const char *person_id_str; + const char *person_timestamp_str; + time_t timestamp; + int i; + int err = 0; + + person_object = 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); + snprintf(xpath_str, sizeof(xpath_str), "%s[%i]/pidf:timestamp", person_prefix, i); + person_timestamp_str = get_xml_text_content(xml_ctx, xpath_str); + if (person_timestamp_str == NULL) + timestamp = time(NULL); + else + timestamp = parse_timestamp(person_timestamp_str); + person = presence_person_new(person_id_str, timestamp); + if (person != NULL) { + err = process_pidf_xml_presence_person_activities(xml_ctx, person, i); + if (err == 0) { + err = process_pidf_xml_presence_person_notes(xml_ctx, person, i); + } + if (err == 0) { + presence_model_add_person(model, person); + } else { + linphone_presence_person_unref(person); + 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_object != NULL) xmlXPathFreeObject(person_object); + + if (err < 0) { + /* Remove all the persons added since there was an error. */ + ms_list_for_each(model->persons, (MSIterateFunc)linphone_presence_person_unref); + } + return err; +} + +static int process_pidf_xml_presence_notes(xmlparsing_context_t *xml_ctx, LinphonePresenceModel *model) { + char xpath_str[MAX_XPATH_LENGTH]; + xmlXPathObjectPtr note_object; + LinphonePresenceNote *note; + const char *note_str; + const char *lang; + int i; + + note_object = 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); + 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); + + 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 (note_object != NULL) xmlXPathFreeObject(note_object); + + return 0; +} + +static LinphonePresenceModel * process_pidf_xml_presence_notification(xmlparsing_context_t *xml_ctx) { + LinphonePresenceModel *model = NULL; + int err; + + if (create_xml_xpath_context(xml_ctx) < 0) + return NULL; + + model = linphone_presence_model_new(); + xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"pidf", (const xmlChar *)"urn:ietf:params:xml:ns:pidf"); + xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"dm", (const xmlChar *)"urn:ietf:params:xml:ns:pidf:data-model"); + xmlXPathRegisterNs(xml_ctx->xpath_ctx, (const xmlChar *)"rpid", (const xmlChar *)"urn:ietf:params:xml:ns:pidf:rpid"); + err = process_pidf_xml_presence_services(xml_ctx, model); + if (err == 0) { + err = process_pidf_xml_presence_persons(xml_ctx, model); + } + if (err == 0) { + err = process_pidf_xml_presence_notes(xml_ctx, model); + } + + if (err < 0) { + linphone_presence_model_unref(model); + model = NULL; + } + + return model; +} + + + + void linphone_core_add_subscriber(LinphoneCore *lc, const char *subscriber, SalOp *op){ - LinphoneFriend *fl=linphone_friend_new_with_addr(subscriber); + LinphoneFriend *fl=linphone_friend_new_with_address(subscriber); if (fl==NULL) return ; fl->insub=op; linphone_friend_set_inc_subscribe_policy(fl,LinphoneSPAccept); fl->inc_subscribe_pending=TRUE; lc->subscribers=ms_list_append(lc->subscribers,(void *)fl); - if (lc->vtable.new_subscription_request!=NULL) { + if (lc->vtable.new_subscription_requested!=NULL) { char *tmp=linphone_address_as_string(fl->uri); - lc->vtable.new_subscription_request(lc,fl,tmp); + lc->vtable.new_subscription_requested(lc,fl,tmp); ms_free(tmp); } } @@ -42,13 +1535,16 @@ void linphone_core_reject_subscriber(LinphoneCore *lc, LinphoneFriend *lf){ linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPDeny); } -void linphone_core_notify_all_friends(LinphoneCore *lc, LinphoneOnlineStatus os){ +void linphone_core_notify_all_friends(LinphoneCore *lc, LinphonePresenceModel *presence){ MSList *elem; - ms_message("Notifying all friends that we are in status %i",os); + LinphonePresenceActivity *activity = linphone_presence_model_get_activity(presence); + char *activity_str = linphone_presence_activity_to_string(activity); + ms_message("Notifying all friends that we are [%s]", activity_str); + if (activity_str != NULL) ms_free(activity_str); for(elem=lc->friends;elem!=NULL;elem=elem->next){ LinphoneFriend *lf=(LinphoneFriend *)elem->data; if (lf->insub){ - linphone_friend_notify(lf,os); + linphone_friend_notify(lf,presence); } } } @@ -58,7 +1554,6 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ char *tmp; LinphoneAddress *uri; LinphoneProxyConfig *cfg; - const char *fixed_contact; uri=linphone_address_new(from); linphone_address_clean(uri); @@ -68,25 +1563,25 @@ 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){ - fixed_contact=sal_op_get_contact(cfg->op); - if (fixed_contact) { - sal_op_set_contact (op,fixed_contact); - ms_message("Contact for next subscribe answer has been fixed using proxy to %s",fixed_contact); + if (sal_op_get_contact(cfg->op)) { + sal_op_set_contact (op,sal_op_get_contact(cfg->op)); + ms_message("Contact for next subscribe answer has been fixed using proxy "/*to %s",fixed_contact*/); } } } + /* check if we answer to this subscription */ - if (linphone_find_friend(lc->friends,uri,&lf)!=NULL){ + if (linphone_find_friend_by_address(lc->friends,uri,&lf)!=NULL){ lf->insub=op; lf->inc_subscribe_pending=TRUE; sal_subscribe_accept(op); linphone_friend_done(lf); /*this will do all necessary actions */ }else{ /* check if this subscriber is in our black list */ - if (linphone_find_friend(lc->subscribers,uri,&lf)){ + if (linphone_find_friend_by_address(lc->subscribers,uri,&lf)){ if (lf->pol==LinphoneSPDeny){ ms_message("Rejecting %s because we already rejected it once.",from); - sal_subscribe_decline(op); + sal_subscribe_decline(op,SalReasonDeclined); } else { /* else it is in wait for approval state, because otherwise it is in the friend list.*/ @@ -101,53 +1596,374 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ ms_free(tmp); } -void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus sal_status){ +void linphone_notify_parse_presence(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result) { + xmlparsing_context_t *xml_ctx; + LinphonePresenceModel *model = NULL; + + if (strcmp(content_type, "application") != 0) { + *result = NULL; + return; + } + + if (strcmp(content_subtype, "pidf+xml") == 0) { + xml_ctx = xmlparsing_context_new(); + xmlSetGenericErrorFunc(xml_ctx, 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); + } else { + ms_error("Unknown content type '%s/%s' for presence", content_type, content_subtype); + } + + /* If no activities are present in the model, add a dummy activity so that linphone_presence_activity_get_type() returns + * the expected result. */ + if (model != NULL) { + LinphonePresenceActivity *activity = linphone_presence_model_get_activity(model); + if (activity == NULL) { + LinphonePresenceBasicStatus basic_status = linphone_presence_model_get_basic_status(model); + LinphonePresenceActivityType acttype; + switch (basic_status) { + case LinphonePresenceBasicStatusOpen: + acttype = LinphonePresenceActivityOnline; + break; + case LinphonePresenceBasicStatusClosed: + default: + acttype = LinphonePresenceActivityOffline; + break; + } + activity = linphone_presence_activity_new(acttype, NULL); + linphone_presence_model_add_activity(model, activity); + } + } + + *result = (SalPresenceModel *)model; +} + +struct _presence_service_obj_st { + xmlTextWriterPtr writer; + const char *contact; + int *err; +}; + +struct _presence_person_obj_st { + xmlTextWriterPtr writer; + int *err; +}; + +struct _presence_activity_obj_st { + xmlTextWriterPtr writer; + int *err; +}; + +struct _presence_note_obj_st { + xmlTextWriterPtr writer; + const char *ns; + int *err; +}; + +static int write_xml_presence_note(xmlTextWriterPtr writer, LinphonePresenceNote *note, const char *ns) { + int err; + if (ns == NULL) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"note"); + } else { + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)ns, (const xmlChar *)"note", NULL); + } + if ((err >= 0) && (note->lang != NULL)) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xml", (const xmlChar *)"lang", NULL, (const xmlChar *)note->lang); + } + if (err >= 0) { + err = xmlTextWriterWriteString(writer, (const xmlChar *)note->content); + } + if (err >= 0) { + err = xmlTextWriterEndElement(writer); + } + return err; +} + +static void write_xml_presence_note_obj(LinphonePresenceNote *note, struct _presence_note_obj_st *st) { + int err = write_xml_presence_note(st->writer, note, st->ns); + if (err < 0) *st->err = err; +} + +static int write_xml_presence_timestamp(xmlTextWriterPtr writer, time_t timestamp) { + int err; + char *timestamp_str = timestamp_to_string(timestamp); + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"timestamp", (const xmlChar *)timestamp_str); + if (timestamp_str) ms_free(timestamp_str); + return err; +} + +static int write_xml_presence_service(xmlTextWriterPtr writer, LinphonePresenceService *service, const char *contact) { + int err = xmlTextWriterStartElement(writer, (const xmlChar *)"tuple"); + if (err >= 0) { + if ((service == NULL) || (service->id == NULL)) { + char *text = generate_presence_id(); + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"id", (const xmlChar *)text); + if (text != NULL) ms_free(text); + } else { + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"id", (const xmlChar *)service->id); + } + } + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"status"); + } + if (err >= 0) { + LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusClosed; + if (service != NULL) basic_status = service->status; + err = xmlTextWriterWriteElement(writer, (const xmlChar *)"basic", (const xmlChar *)presence_basic_status_to_string(basic_status)); + } + if (err >= 0) { + /* Close the "status" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterStartElement(writer, (const xmlChar *)"contact"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"priority", (const xmlChar *)"0.8"); + } + if (err >= 0) { + const char *contact_str; + if ((service == NULL) || (service->contact == NULL)) + contact_str = contact; + else + contact_str = service->contact; + err = xmlTextWriterWriteString(writer, (const xmlChar *)contact_str); + } + if (err >= 0) { + /* Close the "contact" element. */ + err = xmlTextWriterEndElement(writer); + } + if ((err >= 0) && (service != NULL) && (service->notes != NULL)) { + struct _presence_note_obj_st st; + st.writer = writer; + st.ns = NULL; + st.err = &err; + ms_list_for_each2(service->notes, (MSIterate2Func)write_xml_presence_note_obj, &st); + } + if (err >= 0) { + if (service == NULL) + err = write_xml_presence_timestamp(writer, time(NULL)); + else + err = write_xml_presence_timestamp(writer, service->timestamp); + } + if (err >= 0) { + /* Close the "tuple" element. */ + err = xmlTextWriterEndElement(writer); + } + return err; +} + +static bool_t is_valid_activity(LinphonePresenceActivity *activity) { + if ((activity->type == LinphonePresenceActivityOffline) || (activity->type == LinphonePresenceActivityOnline)) + return FALSE; + return TRUE; +} + +static int write_xml_presence_activity(xmlTextWriterPtr writer, LinphonePresenceActivity *activity) { + int err; + + if (is_valid_activity(activity) == FALSE) return 0; + + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"rpid", + (const xmlChar *)presence_activity_type_to_string(activity->type), NULL); + if ((err >= 0) && (activity->description != NULL)) { + err = xmlTextWriterWriteString(writer, (const xmlChar *)activity->description); + } + if (err >= 0) { + err = xmlTextWriterEndElement(writer); + } + return err; +} + +static void write_xml_presence_activity_obj(LinphonePresenceActivity *activity, struct _presence_activity_obj_st *st) { + int err = write_xml_presence_activity(st->writer, activity); + if (err < 0) *st->err = err; +} + +static void person_has_valid_activity(LinphonePresenceActivity *activity, bool_t *has_valid_activities) { + if (is_valid_activity(activity) == TRUE) *has_valid_activities = TRUE; +} + +static bool_t person_has_valid_activities(LinphonePresencePerson *person) { + bool_t has_valid_activities = FALSE; + ms_list_for_each2(person->activities, (MSIterate2Func)person_has_valid_activity, &has_valid_activities); + return has_valid_activities; +} + +static int write_xml_presence_person(xmlTextWriterPtr writer, LinphonePresencePerson *person) { + int err; + + if ((person_has_valid_activities(person) == FALSE) && (person->notes == NULL)) return 0; + + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"dm", (const xmlChar *)"person", NULL); + if (err >= 0) { + if (person->id == NULL) { + char *text = generate_presence_id(); + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"id", (const xmlChar *)text); + if (text != NULL) ms_free(text); + } else { + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"id", (const xmlChar *)person->id); + } + } + if ((err >= 0) && ((person->activities_notes != NULL) || (person_has_valid_activities(person) == TRUE))) { + err = xmlTextWriterStartElementNS(writer, (const xmlChar *)"rpid", (const xmlChar *)"activities", NULL); + if ((err >= 0) && (person->activities_notes != NULL)) { + struct _presence_note_obj_st st; + st.writer = writer; + st.ns = "rpid"; + st.err = &err; + ms_list_for_each2(person->activities_notes, (MSIterate2Func)write_xml_presence_note_obj, &st); + } + if ((err >= 0) && (person->activities != NULL)) { + struct _presence_activity_obj_st st; + st.writer = writer; + st.err = &err; + ms_list_for_each2(person->activities, (MSIterate2Func)write_xml_presence_activity_obj, &st); + } + if (err >= 0) { + /* Close the "activities" element. */ + err = xmlTextWriterEndElement(writer); + } + } + if ((err >= 0) && (person->notes != NULL)) { + struct _presence_note_obj_st st; + st.writer = writer; + st.ns = "dm"; + st.err = &err; + ms_list_for_each2(person->notes, (MSIterate2Func)write_xml_presence_note_obj, &st); + } + if (err >= 0) { + write_xml_presence_timestamp(writer, person->timestamp); + } + if (err >= 0) { + /* Close the "person" element. */ + err = xmlTextWriterEndElement(writer); + } + return err; +} + +static void write_xml_presence_service_obj(LinphonePresenceService *service, struct _presence_service_obj_st *st) { + int err = write_xml_presence_service(st->writer, service, st->contact); + if (err < 0) *st->err = err; +} + +static void write_xml_presence_person_obj(LinphonePresencePerson *person, struct _presence_person_obj_st *st) { + int err = write_xml_presence_person(st->writer, person); + if (err < 0) *st->err = err; +} + +void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presence, const char *contact, char **content) { + LinphonePresenceModel *model; + xmlBufferPtr buf; + xmlTextWriterPtr writer; + int err; + + if ((contact == NULL) || (content == NULL)) return; + + model = (LinphonePresenceModel *)presence; + buf = xmlBufferCreate(); + if (buf == NULL) { + ms_error("Error creating the XML buffer"); + return; + } + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) { + ms_error("Error creating the XML writer"); + return; + } + + err = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + if (err >= 0) { + err = xmlTextWriterStartElementNS(writer, NULL, (const xmlChar *)"presence", (const xmlChar *)"urn:ietf:params:xml:ns:pidf"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"dm", + NULL, (const xmlChar *)"urn:ietf:params:xml:ns:pidf:data-model"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttributeNS(writer, (const xmlChar *)"xmlns", (const xmlChar *)"rpid", + NULL, (const xmlChar *)"urn:ietf:params:xml:ns:pidf:rpid"); + } + if (err >= 0) { + err = xmlTextWriterWriteAttribute(writer, (const xmlChar *)"entity", (const xmlChar *)contact); + } + if (err >= 0) { + if ((model == NULL) || (model->services == NULL)) { + err = write_xml_presence_service(writer, NULL, contact); + } else { + struct _presence_service_obj_st st; + st.writer = writer; + st.contact = contact; + st.err = &err; + ms_list_for_each2(model->services, (MSIterate2Func)write_xml_presence_service_obj, &st); + } + } + if ((err >= 0) && (model != NULL)) { + struct _presence_person_obj_st st; + 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; + st.writer = writer; + st.ns = NULL; + st.err = &err; + ms_list_for_each2(model->notes, (MSIterate2Func)write_xml_presence_note_obj, &st); + } + if (err >= 0) { + /* Close the "presence" element. */ + err = xmlTextWriterEndElement(writer); + } + if (err >= 0) { + err = xmlTextWriterEndDocument(writer); + } + + xmlFreeTextWriter(writer); + if (err > 0) { + /* xmlTextWriterEndDocument returns the size of the content. */ + *content = ms_strdup((char *)buf->content); + } + xmlBufferFree(buf); +} + +void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model){ char *tmp; LinphoneFriend *lf; LinphoneAddress *friend=NULL; - LinphoneOnlineStatus estatus=LinphoneStatusOffline; - - switch(sal_status){ - case SalPresenceOffline: - estatus=LinphoneStatusOffline; - break; - case SalPresenceOnline: - estatus=LinphoneStatusOnline; - break; - case SalPresenceBusy: - estatus=LinphoneStatusBusy; - break; - case SalPresenceBerightback: - estatus=LinphoneStatusBeRightBack; - break; - case SalPresenceAway: - estatus=LinphoneStatusAway; - break; - case SalPresenceOnthephone: - estatus=LinphoneStatusOnThePhone; - break; - case SalPresenceOuttolunch: - estatus=LinphoneStatusOutToLunch; - break; - case SalPresenceDonotdisturb: - estatus=LinphoneStatusDoNotDisturb; - break; - case SalPresenceMoved: - case SalPresenceAltService: - estatus=LinphoneStatusMoved; - break; - } + LinphonePresenceModel *presence = model ? (LinphonePresenceModel *)model:linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline, NULL); + lf=linphone_find_friend_by_out_subscribe(lc->friends,op); + if (lf==NULL && lp_config_get_int(lc->config,"sip","allow_out_of_subscribe_presence",0)){ + const SalAddress *addr=sal_op_get_from_address(op); + lf=NULL; + linphone_find_friend_by_address(lc->friends,(LinphoneAddress*)addr,&lf); + } if (lf!=NULL){ + LinphonePresenceActivity *activity = NULL; + char *activity_str; friend=lf->uri; tmp=linphone_address_as_string(friend); - lf->status=estatus; + activity = linphone_presence_model_get_activity(presence); + activity_str = linphone_presence_activity_to_string(activity); + ms_message("We are notified that [%s] has presence [%s]", tmp, activity_str); + if (activity_str != NULL) ms_free(activity_str); + if (lf->presence != NULL) { + linphone_presence_model_unref(lf->presence); + } + lf->presence = presence; lf->subscribe_active=TRUE; - if (lc->vtable.notify_presence_recv) - lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf); + if (lc->vtable.notify_presence_received) + lc->vtable.notify_presence_received(lc,(LinphoneFriend*)lf); ms_free(tmp); }else{ ms_message("But this person is not part of our friend list, so we don't care."); + linphone_presence_model_unref(presence); } if (ss==SalSubscribeTerminated){ sal_op_release(op); @@ -168,3 +1984,31 @@ void linphone_subscription_closed(LinphoneCore *lc, SalOp *op){ ms_warning("Receiving unsuscribe for unknown in-subscribtion from %s", sal_op_get_from(op)); } } + +LinphonePresenceActivity * linphone_core_create_presence_activity(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description) { + return linphone_presence_activity_new(acttype, description); +} + +LinphonePresenceModel * linphone_core_create_presence_model(LinphoneCore *lc) { + return linphone_presence_model_new(); +} + +LinphonePresenceModel * linphone_core_create_presence_model_with_activity(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description) { + return linphone_presence_model_new_with_activity(acttype, description); +} + +LinphonePresenceModel * linphone_core_create_presence_model_with_activity_and_note(LinphoneCore *lc, LinphonePresenceActivityType acttype, const char *description, const char *note, const char *lang) { + return linphone_presence_model_new_with_activity_and_note(acttype, description, note, lang); +} + +LinphonePresenceNote * linphone_core_create_presence_note(LinphoneCore *lc, const char *content, const char *lang) { + return linphone_presence_note_new(content, lang); +} + +LinphonePresencePerson * linphone_core_create_presence_person(LinphoneCore *lc, const char *id) { + return linphone_presence_person_new(id); +} + +LinphonePresenceService * linphone_core_create_presence_service(LinphoneCore *lc, const char *id, LinphonePresenceBasicStatus basic_status, const char *contact) { + return linphone_presence_service_new(id, basic_status, contact); +} diff --git a/coreapi/private.h b/coreapi/private.h index 0ba7c2db0..0d3e47815 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -31,7 +31,7 @@ extern "C" { #include "linphonefriend.h" #include "linphone_tunnel.h" #include "linphonecore_utils.h" -#include "sal.h" +#include "sal/sal.h" #include "sipsetup.h" #ifdef HAVE_CONFIG_H @@ -80,6 +80,8 @@ struct _LinphoneCallParams{ LinphoneMediaEncryption media_encryption; PayloadType *audio_codec; /*audio codec currently in use */ PayloadType *video_codec; /*video codec currently in use */ + MSVideoSize sent_vsize; /* Size of the video currently being sent */ + MSVideoSize recv_vsize; /* Size of the video currently being received */ int down_bw; int up_bw; int down_ptime; @@ -91,6 +93,7 @@ struct _LinphoneCallParams{ bool_t in_conference; /*in conference mode */ bool_t pad; bool_t low_bandwidth; + LinphonePrivacyMask privacy; }; struct _LinphoneCallLog{ @@ -128,7 +131,7 @@ struct _LinphoneChatMessage { LinphoneChatRoom* chat_room; LinphoneChatMessageDir dir; char* message; - LinphoneChatMessageStateChangeCb cb; + LinphoneChatMessageStateChangedCb cb; void* cb_ud; void* message_userdata; char* external_body_url; @@ -138,6 +141,7 @@ struct _LinphoneChatMessage { SalCustomHeader *custom_headers; LinphoneChatMessageState state; bool_t is_read; + unsigned int storage_id; }; typedef struct StunCandidate{ @@ -153,7 +157,6 @@ struct _LinphoneCall SalMediaDescription *localdesc; SalMediaDescription *resultdesc; LinphoneCallDir dir; - LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/ struct _RtpProfile *audio_profile; struct _RtpProfile *video_profile; struct _LinphoneCallLog *log; @@ -162,7 +165,8 @@ struct _LinphoneCall 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 state; + LinphoneCallState prevstate; LinphoneCallState transfer_state; /*idle if no transfer*/ LinphoneReason reason; LinphoneProxyConfig *dest_proxy; @@ -193,6 +197,10 @@ struct _LinphoneCall 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; + bool_t refer_pending; bool_t media_pending; bool_t audio_muted; @@ -215,10 +223,10 @@ struct _LinphoneCall }; -LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params); +LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); - +void linphone_call_set_contact_op(LinphoneCall* call); /* private: */ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote); void linphone_call_log_completed(LinphoneCall *call); @@ -230,17 +238,27 @@ void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo void linphone_core_update_proxy_register(LinphoneCore *lc); void linphone_core_refresh_subscribes(LinphoneCore *lc); int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error); +const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); -int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os); +int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphonePresenceModel *presence); void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message); +void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj); +void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc); +/* + * returns service route as defined in as defined by rfc3608, might be a list instead of just one. + * Can be NULL + * */ +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_notify(LinphoneFriend *lf, LinphoneOnlineStatus os); +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); -int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen); +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(); @@ -277,22 +295,24 @@ static inline void set_string(char **dest, const char *src){ #define PAYLOAD_TYPE_ENABLED PAYLOAD_TYPE_USER_FLAG_0 -SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os); void linphone_process_authentication(LinphoneCore* lc, SalOp *op); void linphone_authentication_ok(LinphoneCore *lc, SalOp *op); void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from); -void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status); +void linphone_core_send_presence(LinphoneCore *lc, LinphonePresenceModel *presence); +void linphone_notify_parse_presence(SalOp *op, const char *content_type, const char *content_subtype, const char *body, SalPresenceModel **result); +void linphone_notify_convert_presence_to_xml(SalOp *op, SalPresenceModel *presence, const char *contact, char **content); +void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model); void linphone_proxy_config_process_authentication_failure(LinphoneCore *lc, SalOp *op); void linphone_subscription_answered(LinphoneCore *lc, SalOp *op); void linphone_subscription_closed(LinphoneCore *lc, SalOp *op); -MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *fri, LinphoneFriend **lf); - void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt); int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); +void linphone_core_resolve_stun_server(LinphoneCore *lc); +const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc); void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params); int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call); void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call); @@ -308,7 +328,7 @@ LinphoneFriend * linphone_friend_new_from_config_file(struct _LinphoneCore *lc, void linphone_proxy_config_update(LinphoneProxyConfig *cfg); void linphone_proxy_config_get_contact(LinphoneProxyConfig *cfg, const char **ip, int *port); LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri); -const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to, const char **route); +const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to); int linphone_core_get_local_ip_for(int type, const char *dest, char *result); LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(struct _LpConfig *config, int index); @@ -321,7 +341,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag void linphone_core_play_tone(LinphoneCore *lc); void linphone_call_init_stats(LinphoneCallStats *stats, int type); - +void linphone_call_fix_call_parameters(LinphoneCall *call); void linphone_call_init_audio_stream(LinphoneCall *call); void linphone_call_init_video_stream(LinphoneCall *call); void linphone_call_init_media_streams(LinphoneCall *call); @@ -337,13 +357,14 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call); const char * linphone_core_get_identity(LinphoneCore *lc); -const char * linphone_core_get_route(LinphoneCore *lc); + void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float progresses); 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_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); @@ -372,7 +393,6 @@ struct _LinphoneProxyConfig char *realm; char *contact_params; int expires; - int reg_time; SalOp *op; char *type; struct _SipSetupContext *ssctx; @@ -384,9 +404,12 @@ struct _LinphoneProxyConfig bool_t reg_sendregister; bool_t publish; bool_t dial_escape_plus; + bool_t send_publish; + bool_t pad[3]; void* user_data; time_t deletion_date; LinphoneReason error; + LinphonePrivacyMask privacy; }; struct _LinphoneAuthInfo @@ -396,6 +419,7 @@ struct _LinphoneAuthInfo char *userid; char *passwd; char *ha1; + char *domain; int usecount; time_t last_use_time; bool_t works; @@ -416,14 +440,16 @@ struct _LinphoneFriend{ SalOp *insub; SalOp *outsub; LinphoneSubscribePolicy pol; - LinphoneOnlineStatus status; + LinphonePresenceModel *presence; struct _LinphoneCore *lc; BuddyInfo *info; char *refkey; + void *up; bool_t subscribe; bool_t subscribe_active; bool_t inc_subscribe_pending; bool_t commit; + bool_t initial_subscribes_sent; /*used to know if initial subscribe message was sent or not*/ }; @@ -473,10 +499,10 @@ typedef struct net_config char *nat_address; /* may be IP or host name */ char *nat_address_ip; /* ip translated from nat_address */ char *stun_server; - char *relay; + struct addrinfo *stun_addrinfo; + SalResolverContext * stun_res; int download_bw; int upload_bw; - int firewall_policy; int mtu; bool_t nat_sdp_only; }net_config_t; @@ -518,7 +544,6 @@ typedef struct video_config{ bool_t show_local; bool_t display; bool_t selfview; /*during calls*/ - const char *displaytype; }video_config_t; typedef struct ui_config @@ -587,14 +612,13 @@ struct _LinphoneCore MSList *bl_reqs; MSList *subscribers; /* unknown subscribers */ int minutes_away; - LinphoneOnlineStatus presence_mode; - char *alt_contact; + LinphonePresenceModel *presence_model; void *data; char *play_file; char *rec_file; time_t prevtime; int audio_bw; - LinphoneWaitingCallback wait_cb; + LinphoneCoreWaitingCallback wait_cb; void *wait_ctx; unsigned long video_window_id; unsigned long preview_window_id; @@ -633,6 +657,23 @@ struct _LinphoneCore #endif //BUILD_UPNP }; + +struct _LinphoneEvent{ + LinphoneSubscriptionDir dir; + LinphoneCore *lc; + SalOp *op; + LinphoneSubscriptionState subscription_state; + LinphonePublishState publish_state; + LinphoneReason reason; + void *userdata; + int refcnt; + char *name; + LinphoneAddress *from; + LinphoneAddress *resource_addr; + bool_t terminating; +}; + + LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); void linphone_tunnel_destroy(LinphoneTunnel *tunnel); void linphone_tunnel_configure(LinphoneTunnel *tunnel); @@ -715,8 +756,8 @@ void linphone_upnp_destroy(LinphoneCore *lc); #ifdef MSG_STORAGE_ENABLED sqlite3 * linphone_message_storage_init(); +void linphone_message_storage_init_chat_rooms(LinphoneCore *lc); #endif -void linphone_chat_message_store(LinphoneChatMessage *msg); void linphone_chat_message_store_state(LinphoneChatMessage *msg); void linphone_core_message_storage_init(LinphoneCore *lc); void linphone_core_message_storage_close(LinphoneCore *lc); @@ -729,6 +770,22 @@ typedef enum _LinphoneToneID{ }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); +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_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); #ifdef __cplusplus diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 05258c1d1..a353d862e 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -47,6 +47,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj 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); } /** @@ -86,10 +87,13 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->dial_prefix!=NULL) ms_free(obj->dial_prefix); 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); + ms_free(obj); } /** * Returns a boolean indicating that the user is sucessfully registered on the proxy. + * @deprecated Use linphone_proxy_config_get_state() instead. **/ bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){ return obj->state == LinphoneRegistrationOk; @@ -111,7 +115,7 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char * obj->reg_proxy=NULL; if (server_addr!=NULL && strlen(server_addr)>0){ - if (strstr(server_addr,"sip:")==NULL){ + if (strstr(server_addr,"sip:")==NULL && strstr(server_addr,"sips:")==NULL){ modified=ms_strdup_printf("sip:%s",server_addr); addr=linphone_address_new(modified); ms_free(modified); @@ -179,11 +183,11 @@ int linphone_proxy_config_set_route(LinphoneProxyConfig *obj, const char *route) ms_free(obj->reg_route); obj->reg_route=NULL; } - if (route!=NULL){ + if (route!=NULL && route[0] !='\0'){ SalAddress *addr; char *tmp; /*try to prepend 'sip:' */ - if (strstr(route,"sip:")==NULL){ + if (strstr(route,"sip:")==NULL && strstr(route,"sips:")==NULL){ tmp=ms_strdup_printf("sip:%s",route); }else tmp=ms_strdup(route); addr=sal_address_new(tmp); @@ -224,7 +228,7 @@ void linphone_proxy_config_enableregister(LinphoneProxyConfig *obj, bool_t val){ /** * Sets the registration expiration time in seconds. **/ -void linphone_proxy_config_expires(LinphoneProxyConfig *obj, int val){ +void linphone_proxy_config_set_expires(LinphoneProxyConfig *obj, int val){ if (val<0) val=600; obj->expires=val; } @@ -242,87 +246,136 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){ * linphone_proxy_config_done() to commit the changes. **/ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ + if (obj->publish && obj->publish_op){ + /*unpublish*/ + sal_publish_presence(obj->publish_op,NULL,NULL,0,(SalPresenceModel *)NULL); + sal_op_release(obj->publish_op); + obj->publish_op=NULL; + } if (obj->reg_sendregister){ /* unregister */ - if (obj->state != LinphoneRegistrationNone && obj->state != LinphoneRegistrationCleared) { + if (obj->state == LinphoneRegistrationOk + || obj->state == LinphoneRegistrationProgress) { sal_unregister(obj->op); } } } -void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc) -{ +void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc){ obj->lc=lc; linphone_proxy_config_done(obj); } -static char *guess_contact_for_register(LinphoneProxyConfig *obj){ +void linphone_proxy_config_stop_refreshing(LinphoneProxyConfig *obj){ + if (obj->publish_op){ + sal_op_release(obj->publish_op); + obj->publish_op=NULL; + } + if (obj->op){ + sal_op_release(obj->op); + obj->op=NULL; + } +} + +LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ + LinphoneAddress *ret=NULL; LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); - char *ret=NULL; + const char *host; if (proxy==NULL) return NULL; host=linphone_address_get_domain (proxy); if (host!=NULL){ int localport = -1; - char localip_tmp[LINPHONE_IPADDR_SIZE] = {'\0'}; const char *localip = NULL; char *tmp; - LCSipTransports tr; + char *tmp2; + LinphoneAddress *identity; LinphoneAddress *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); + } + } + else { + tmp = strdup(obj->reg_identity); + } - contact=linphone_address_new(obj->reg_identity); + 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 - if(localip == NULL) { - localip = localip_tmp; - linphone_core_get_local_ip(obj->lc,host,localip_tmp); - } - if(localport == -1) { - localport = linphone_core_get_sip_port(obj->lc); - } - linphone_address_set_port_int(contact,localport); +#endif //BUILD_UPNP + + + linphone_address_set_port(contact,localport); linphone_address_set_domain(contact,localip); linphone_address_set_display_name(contact,NULL); - - 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"); - } - } - tmp=linphone_address_as_string_uri_only(contact); - if (obj->contact_params) - ret=ms_strdup_printf("<%s;%s>",tmp,obj->contact_params); - else ret=ms_strdup_printf("<%s>",tmp); - linphone_address_destroy(contact); + + ret=contact; + + linphone_address_destroy (proxy); ms_free(tmp); } - linphone_address_destroy (proxy); return ret; } + 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); - contact=guess_contact_for_register(obj); - sal_op_set_contact(obj->op,contact); - ms_free(contact); + if ((contact=guess_contact_for_register(obj))) { + sal_op_set_contact(obj->op,contact); +#ifndef USE_BELLESIP + ms_free(contact); +#else + linphone_address_destroy(contact); +#endif + } sal_op_set_user_pointer(obj->op,obj); - if (sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)==0) { + if (sal_register(obj->op,proxy_string,obj->reg_identity,obj->expires)==0) { linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress,"Registration in progress"); } else { linphone_proxy_config_set_state(obj,LinphoneRegistrationFailed,"Registration failed"); } + ms_free(proxy_string); } } @@ -788,16 +841,23 @@ void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm if (realm!=NULL) cfg->realm=ms_strdup(realm); } -int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, - LinphoneOnlineStatus presence_mode){ - int err; - SalOp *op=sal_op_new(proxy->lc->sal); - sal_op_set_route(op,proxy->reg_proxy); - err=sal_publish(op,linphone_proxy_config_get_identity(proxy), - linphone_proxy_config_get_identity(proxy),linphone_online_status_to_sal(presence_mode)); - if (proxy->publish_op!=NULL) - sal_op_release(proxy->publish_op); - proxy->publish_op=op; +int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePresenceModel *presence){ + int err=0; + + if (proxy->state==LinphoneRegistrationOk || proxy->state==LinphoneRegistrationCleared){ + if (proxy->publish_op==NULL){ + proxy->publish_op=sal_op_new(proxy->lc->sal); + sal_op_set_route(proxy->publish_op,proxy->reg_proxy); + sal_op_set_from(proxy->publish_op,linphone_proxy_config_get_identity(proxy)); + 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_address_unref(addr); + } + } + err=sal_publish_presence(proxy->publish_op,NULL,NULL,proxy->expires,(SalPresenceModel *)presence); + }else proxy->send_publish=TRUE; /*otherwise do not send publish if registration is in progress, this will be done later*/ return err; } @@ -903,9 +963,9 @@ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cf ms_error("linphone_core_remove_proxy_config: LinphoneProxyConfig %p is not known by LinphoneCore (programming error?)",cfg); return; } - lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,(void *)cfg); + lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,cfg); /* add to the list of destroyed proxies, so that the possible unREGISTER request can succeed authentication */ - lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,(void *)cfg); + lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,cfg); cfg->deletion_date=ms_time(NULL); if (cfg->state==LinphoneRegistrationOk){ /* this will unREGISTER */ @@ -1004,6 +1064,7 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC lp_config_set_int(config,key,"publish",obj->publish); lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus); lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix); + lp_config_set_int(config,key,"privacy",obj->privacy); } @@ -1047,6 +1108,8 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config 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))); + return cfg; } @@ -1121,12 +1184,14 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){ } if (can_register(cfg)){ linphone_proxy_config_register(cfg); - if (cfg->publish && cfg->publish_op==NULL){ - linphone_proxy_config_send_publish(cfg,lc->presence_mode); - } cfg->commit=FALSE; + if (cfg->publish) cfg->send_publish=TRUE; } } + if (cfg->send_publish && (cfg->state==LinphoneRegistrationOk || cfg->state==LinphoneRegistrationCleared)){ + linphone_proxy_config_send_publish(cfg,lc->presence_model); + cfg->send_publish=FALSE; + } } void linphone_proxy_config_set_sip_setup(LinphoneProxyConfig *cfg, const char *type){ @@ -1249,9 +1314,19 @@ 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; - cfg->state=state; - if (lc && lc->vtable.registration_state_changed){ - lc->vtable.registration_state_changed(lc,cfg,state,message); + + + 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*/ + cfg->state=state; + if (lc && lc->vtable.registration_state_changed){ + lc->vtable.registration_state_changed(lc,cfg,state,message); + } + } else { + /*state already reported*/ } } @@ -1288,4 +1363,34 @@ void linphone_proxy_config_set_error(LinphoneProxyConfig *cfg,LinphoneReason err cfg->error = error; } +const LinphoneAddress* linphone_proxy_config_get_service_route(const LinphoneProxyConfig* cfg) { + return cfg->op?(const LinphoneAddress*) sal_op_get_service_route(cfg->op):NULL; +} +const char* linphone_proxy_config_get_transport(const LinphoneProxyConfig *cfg) { + const char* addr=NULL; + const char* ret="udp"; /*default value*/ + SalAddress* route_addr=NULL; + if (linphone_proxy_config_get_service_route(cfg)) { + route_addr=(SalAddress*)linphone_proxy_config_get_service_route(cfg); + } else if (linphone_proxy_config_get_route(cfg)) { + addr=linphone_proxy_config_get_route(cfg); + } else if(linphone_proxy_config_get_addr(cfg)) { + addr=linphone_proxy_config_get_addr(cfg); + } else { + ms_error("Cannot guess transport for proxy with identity [%s]",linphone_proxy_config_get_identity(cfg)); + return NULL; + } + if ((route_addr || (route_addr=sal_address_new(addr))) && sal_address_get_transport(route_addr)) { + ret=sal_transport_to_string(sal_address_get_transport(route_addr)); + if (!linphone_proxy_config_get_service_route(cfg)) sal_address_destroy(route_addr); /*destroy except for service route*/ + } + + return ret; +} +void linphone_proxy_config_set_privacy(LinphoneProxyConfig *params, LinphonePrivacyMask privacy) { + params->privacy=privacy; +} +LinphonePrivacyMask linphone_proxy_config_get_privacy(const LinphoneProxyConfig *params) { + return params->privacy; +} diff --git a/coreapi/sal.c b/coreapi/sal.c index 1411407a8..25fa8dcd8 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -22,8 +22,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The purpose of this layer is too allow experiment different call signaling protocols and implementations under linphone, for example SIP, JINGLE... **/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "sal/sal.h" + +#include -#include "sal.h" const char* sal_transport_to_string(SalTransport transport) { switch (transport) { case SalTransportUDP:return "udp"; @@ -38,6 +43,7 @@ const char* sal_transport_to_string(SalTransport transport) { } SalTransport sal_transport_parse(const char* param) { + if (!param) return SalTransportUDP; if (strcasecmp("udp",param)==0) return SalTransportUDP; if (strcasecmp("tcp",param)==0) return SalTransportTCP; if (strcasecmp("tls",param)==0) return SalTransportTLS; @@ -227,6 +233,14 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD } return result; } +static void assign_address(SalAddress** address, const char *value){ + if (*address){ + sal_address_destroy(*address); + *address=NULL; + } + if (value) + *address=sal_address_new(value); +} static void assign_string(char **str, const char *arg){ if (*str){ @@ -237,20 +251,78 @@ 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; +} +const SalAddress* sal_op_get_contact_address(const SalOp *op) { + return ((SalOpBase*)op)->contact_address; +} +#endif +#define SET_PARAM(op,name) \ + char* name##_string=NULL; \ + assign_address(&((SalOpBase*)op)->name##_address,name); \ + if (((SalOpBase*)op)->name##_address) { \ + name##_string=sal_address_as_string(((SalOpBase*)op)->name##_address); \ + }\ + 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){ - assign_string(&((SalOpBase*)op)->route,route); + char* route_string=(void *)0; + SalOpBase* op_base = (SalOpBase*)op; + if (op_base->route_addresses) { + ms_list_for_each(op_base->route_addresses,(void (*)(void *))sal_address_destroy); + op_base->route_addresses=ms_list_free(op_base->route_addresses); + } + if (route) { + op_base->route_addresses=ms_list_append(NULL,NULL); + assign_address((SalAddress**)&(op_base->route_addresses->data),route); + route_string=sal_address_as_string((SalAddress*)op_base->route_addresses->data); \ + } + assign_string(&op_base->route,route_string); \ + if(route_string) ms_free(route_string); +} +const MSList* sal_op_get_route_addresses(const SalOp *op) { + return ((SalOpBase*)op)->route_addresses; +} +void sal_op_set_route_address(SalOp *op, const SalAddress *address){ + char* address_string=sal_address_as_string(address); /*can probably be optimized*/ + sal_op_set_route(op,address_string); + ms_free(address_string); +} +void sal_op_add_route_address(SalOp *op, const SalAddress *address){ + SalOpBase* op_base = (SalOpBase*)op; + if (op_base->route_addresses) { + op_base->route_addresses=ms_list_append(op_base->route_addresses,(void*)sal_address_clone(address)); + } else { + sal_op_set_route_address(op,address); + } } - void sal_op_set_from(SalOp *op, const char *from){ - assign_string(&((SalOpBase*)op)->from,from); + SET_PARAM(op,from); +} +void sal_op_set_from_address(SalOp *op, const SalAddress *from){ + char* address_string=sal_address_as_string(from); /*can probably be optimized*/ + sal_op_set_from(op,address_string); + ms_free(address_string); } - void sal_op_set_to(SalOp *op, const char *to){ - assign_string(&((SalOpBase*)op)->to,to); + SET_PARAM(op,to); +} +void sal_op_set_to_address(SalOp *op, const SalAddress *to){ + char* address_string=sal_address_as_string(to); /*can probably be optimized*/ + sal_op_set_to(op,address_string); + ms_free(address_string); } void sal_op_set_user_pointer(SalOp *op, void *up){ @@ -264,20 +336,22 @@ Sal *sal_op_get_sal(const SalOp *op){ const char *sal_op_get_from(const SalOp *op){ return ((SalOpBase*)op)->from; } +const SalAddress *sal_op_get_from_address(const SalOp *op){ + return ((SalOpBase*)op)->from_address; +} const char *sal_op_get_to(const SalOp *op){ return ((SalOpBase*)op)->to; } -const char *sal_op_get_contact(const SalOp *op){ - return ((SalOpBase*)op)->contact; -} - -const char *sal_op_get_remote_contact(const SalOp *op){ - return ((SalOpBase*)op)->remote_contact; +const SalAddress *sal_op_get_to_address(const SalOp *op){ + return ((SalOpBase*)op)->to_address; } const char *sal_op_get_route(const SalOp *op){ +#ifdef BELLE_SIP +ms_fatal("sal_op_get_route not supported, use sal_op_get_route_addresses instead"); +#endif return ((SalOpBase*)op)->route; } @@ -305,15 +379,39 @@ void __sal_op_init(SalOp *b, Sal *sal){ } void __sal_op_set_network_origin(SalOp *op, const char *origin){ - assign_string(&((SalOpBase*)op)->origin,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_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); + ms_free(address_string); +} void __sal_op_free(SalOp *op){ SalOpBase *b=(SalOpBase *)op; + if (b->from_address){ + sal_address_destroy(b->from_address); + b->from_address=NULL; + } + if (b->to_address){ + sal_address_destroy(b->to_address); + b->to_address=NULL; + } + + if (b->service_route){ + sal_address_destroy(b->service_route); + b->service_route=NULL; + } + + if (b->origin_address){ + sal_address_destroy(b->origin_address); + b->origin_address=NULL; + } + if (b->from) { ms_free(b->from); b->from=NULL; @@ -326,10 +424,16 @@ 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; @@ -347,9 +451,18 @@ void __sal_op_free(SalOp *op){ if (b->remote_media) sal_media_description_unref(b->remote_media); if (b->call_id) - ms_free(b->call_id); - if (b->custom_headers) - sal_custom_header_free(b->custom_headers); + ms_free((void*)b->call_id); + if (b->service_route) { + sal_address_destroy(b->service_route); + } + if (b->route_addresses){ + ms_list_for_each(b->route_addresses,(void (*)(void*)) sal_address_destroy); + b->route_addresses=ms_list_free(b->route_addresses); + } + if (b->recv_custom_headers) + sal_custom_header_free(b->recv_custom_headers); + if (b->sent_custom_headers) + sal_custom_header_free(b->sent_custom_headers); ms_free(op); } @@ -362,71 +475,154 @@ SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) { new_auth_info->username=auth_info->username?ms_strdup(auth_info->username):NULL; new_auth_info->userid=auth_info->userid?ms_strdup(auth_info->userid):NULL; new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL; + new_auth_info->domain=auth_info->realm?ms_strdup(auth_info->domain):NULL; new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL; return new_auth_info; } -void sal_auth_info_delete(const SalAuthInfo* auth_info) { +void sal_auth_info_delete(SalAuthInfo* auth_info) { if (auth_info->username) ms_free(auth_info->username); if (auth_info->userid) ms_free(auth_info->userid); if (auth_info->realm) ms_free(auth_info->realm); + if (auth_info->domain) ms_free(auth_info->domain); if (auth_info->password) ms_free(auth_info->password); - ms_free((void*)auth_info); + if (auth_info->ha1) ms_free(auth_info->ha1); + if (auth_info->certificates) sal_certificates_chain_delete(auth_info->certificates); + if (auth_info->key) sal_signing_key_delete(auth_info->key); + ms_free(auth_info); } -SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){ - SalCustomHeader *h=ms_new0(SalCustomHeader,1); - h->header_name=ms_strdup(name); - h->header_value=ms_strdup(value); - h->node.data=h; - return (SalCustomHeader*)ms_list_append_link((MSList*)ch,(MSList*)h); -} -const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ - const MSList *it; - for (it=(const MSList*)ch;it!=NULL;it=it->next){ - const SalCustomHeader *itch=(const SalCustomHeader *)it; - if (strcasecmp(itch->header_name,name)==0) - return itch->header_value; + +const char* sal_stream_type_to_string(SalStreamType type) { + switch (type) { + case SalAudio:return "audio"; + case SalVideo:return "video"; + default: return "other"; } - return NULL; } -static void sal_custom_header_uninit(SalCustomHeader *ch){ - ms_free(ch->header_name); - ms_free(ch->header_value); -} - -void sal_custom_header_free(SalCustomHeader *ch){ - ms_list_for_each((MSList*)ch,(void (*)(void*))sal_custom_header_uninit); - ms_list_free((MSList *)ch); -} - -SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch){ - const MSList *it; - SalCustomHeader *ret=NULL; - for (it=(const MSList*)ch;it!=NULL;it=it->next){ - const SalCustomHeader *itch=(const SalCustomHeader *)it; - ret=sal_custom_header_append(ret,itch->header_name,itch->header_value); +const char* sal_media_proto_to_string(SalMediaProto type) { + switch (type) { + case SalProtoRtpAvp:return "RTP/AVP"; + case SalProtoRtpSavp:return "RTP/SAVP"; + default: return "unknown"; } - return ret; } -const SalCustomHeader *sal_op_get_custom_header(SalOp *op){ - SalOpBase *b=(SalOpBase *)op; - return b->custom_headers; -} -/* - * Warning: this function takes owneship of the custom headers - */ -void sal_op_set_custom_header(SalOp *op, SalCustomHeader* ch){ - SalOpBase *b=(SalOpBase *)op; - if (b->custom_headers){ - sal_custom_header_free(b->custom_headers); - b->custom_headers=NULL; +const char* sal_stream_dir_to_string(SalStreamDir type) { + switch (type) { + case SalStreamSendRecv:return "sendrecv"; + case SalStreamSendOnly:return "sendonly"; + case SalStreamRecvOnly:return "recvonly"; + case SalStreamInactive:return "inative"; + default: return "unknown"; } - b->custom_headers=ch; + +} + +const char* sal_reason_to_string(const SalReason reason) { + switch (reason) { + case SalReasonDeclined : return "SalReasonDeclined"; + case SalReasonBusy: return "SalReasonBusy"; + case SalReasonRedirect: return "SalReasonRedirect"; + case SalReasonTemporarilyUnavailable: return "SalReasonTemporarilyUnavailable"; + case SalReasonNotFound: return "SalReasonNotFound"; + case SalReasonDoNotDisturb: return "SalReasonDoNotDisturb"; + case SalReasonMedia: return "SalReasonMedia"; + case SalReasonForbidden: return "SalReasonForbidden"; + case SalReasonUnknown: return "SalReasonUnknown"; + case SalReasonServiceUnavailable: return "SalReasonServiceUnavailable"; + case SalReasonNotAcceptable: return "SalReasonNotAcceptable"; + default: return "Unkown reason"; + } +} +const SalAddress* sal_op_get_service_route(const SalOp *op) { + return ((SalOpBase*)op)->service_route; +} +void sal_op_set_service_route(SalOp *op,const SalAddress* service_route) { + if (((SalOpBase*)op)->service_route) + sal_address_destroy(((SalOpBase*)op)->service_route); + + ((SalOpBase*)op)->service_route=service_route?sal_address_clone(service_route):NULL; +} + +const char* sal_presence_status_to_string(const SalPresenceStatus status) { + switch (status) { + case SalPresenceOffline: return "SalPresenceOffline"; + case SalPresenceOnline: return "SalPresenceOnline"; + case SalPresenceBusy: return "SalPresenceBusy"; + case SalPresenceBerightback: return "SalPresenceBerightback"; + case SalPresenceAway: return "SalPresenceAway"; + case SalPresenceOnthephone: return "SalPresenceOnthephone"; + case SalPresenceOuttolunch: return "SalPresenceOuttolunch"; + case SalPresenceDonotdisturb: return "SalPresenceDonotdisturb"; + case SalPresenceMoved: return "SalPresenceMoved"; + case SalPresenceAltService: return "SalPresenceAltService"; + default : return "unknown"; + } + +} +const char* sal_privacy_to_string(SalPrivacy privacy) { + switch(privacy) { + case SalPrivacyUser: return "user"; + case SalPrivacyHeader: return "header"; + case SalPrivacySession: return "session"; + case SalPrivacyId: return "id"; + case SalPrivacyNone: return "none"; + case SalPrivacyCritical: return "critical"; + default: return NULL; + } +} + +static void remove_trailing_spaces(char *line){ + int i; + for(i=strlen(line)-1;i>=0;--i){ + if (isspace(line[i])) line[i]='\0'; + else break; + } +} + +static int line_get_value(const char *input, const char *key, char *value, size_t value_size, int *read){ + const char *end=strchr(input,'\n'); + char line[256]={0}; + char key_candidate[256]; + char *equal; + size_t len; + if (!end) len=strlen(input); + else len=end +1 -input; + *read=len; + strncpy(line,input,MIN(len,sizeof(line))); + equal=strchr(line,'='); + if (!equal) return FALSE; + *equal='\0'; + if (sscanf(line,"%s",key_candidate)!=1) return FALSE; + if (strcasecmp(key,key_candidate)==0){ + equal++; + remove_trailing_spaces(equal); + strncpy(value,equal,value_size-1); + value[value_size-1]='\0'; + return TRUE; + } + return FALSE; +} + +int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size){ + int read=0; + + do{ + if (line_get_value(data,key,value,value_size,&read)) + return TRUE; + data+=read; + }while(read!=0); + return FALSE; +} + +int sal_body_has_type(const SalBody *body, const char *type, const char *subtype){ + return body->type && body->subtype + && strcmp(body->type,type)==0 + && strcmp(body->subtype,subtype)==0; } diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c deleted file mode 100644 index 284773c9d..000000000 --- a/coreapi/sal_eXosip2.c +++ /dev/null @@ -1,2688 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -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. -*/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "sal_eXosip2.h" -#include "offeranswer.h" - -#ifdef ANDROID -// Necessary to make it linked -static void for_linker() { eXosip_transport_hook_register(NULL); } -#endif -static bool_t call_failure(Sal *sal, eXosip_event_t *ev); - -static void text_received(Sal *sal, eXosip_event_t *ev); - -static void masquerade_via(osip_message_t *msg, const char *ip, const char *port); -static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact); -static void update_contact_from_response(SalOp *op, osip_message_t *response); - - -void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){ - void *data; - while(!osip_list_eol(l,0)) { - data=osip_list_get(l,0); - osip_list_remove(l,0); - if (data) freefunc(data); - } -} - -void sal_get_default_local_ip(Sal *sal, int address_family,char *ip, size_t iplen){ - if (eXosip_guess_localip(address_family,ip,iplen)<0){ - /*default to something */ - strncpy(ip,address_family==AF_INET6 ? "::1" : "127.0.0.1",iplen); - ms_error("Could not find default routable ip address !"); - } -} - -static SalOp * sal_find_call(Sal *sal, int cid){ - const MSList *elem; - SalOp *op; - for(elem=sal->calls;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->cid==cid) return op; - } - return NULL; -} - -static void sal_add_call(Sal *sal, SalOp *op){ - sal->calls=ms_list_append(sal->calls,op); -} - -static void sal_remove_call(Sal *sal, SalOp *op){ - sal->calls=ms_list_remove(sal->calls, op); -} - -static SalOp * sal_find_register(Sal *sal, int rid){ - const MSList *elem; - SalOp *op; - for(elem=sal->registers;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->rid==rid) return op; - } - return NULL; -} - -static void sal_add_register(Sal *sal, SalOp *op){ - sal->registers=ms_list_append(sal->registers,op); -} - -static void sal_remove_register(Sal *sal, int rid){ - MSList *elem; - SalOp *op; - for(elem=sal->registers;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->rid==rid) { - sal->registers=ms_list_remove_link(sal->registers,elem); - return; - } - } -} - -static SalOp * sal_find_other(Sal *sal, osip_message_t *message){ - const MSList *elem; - SalOp *op; - osip_call_id_t *callid=osip_message_get_call_id(message); - if (callid==NULL) { - ms_error("There is no call-id in this message !"); - return NULL; - } - for(elem=sal->other_transactions;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (osip_call_id_match(callid,op->call_id)==0) return op; - } - return NULL; -} - -void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request){ - osip_call_id_t *callid=osip_message_get_call_id(request); - if (callid==NULL) { - ms_error("There is no call id in the request !"); - return; - } - osip_call_id_clone(callid,&op->call_id); - sal->other_transactions=ms_list_append(sal->other_transactions,op); -} - -static void sal_remove_other(Sal *sal, SalOp *op){ - sal->other_transactions=ms_list_remove(sal->other_transactions,op); -} - - -static void sal_add_pending_auth(Sal *sal, SalOp *op){ - sal->pending_auths=ms_list_append(sal->pending_auths,op); -} - - -static void sal_remove_pending_auth(Sal *sal, SalOp *op){ - sal->pending_auths=ms_list_remove(sal->pending_auths,op); -} - -void sal_exosip_fix_route(SalOp *op){ - if (sal_op_get_route(op)!=NULL){ - osip_route_t *rt=NULL; - osip_uri_param_t *lr_param=NULL; - - osip_route_init(&rt); - if (osip_route_parse(rt,sal_op_get_route(op))<0){ - ms_warning("Bad route %s!",sal_op_get_route(op)); - sal_op_set_route(op,NULL); - }else{ - /* check if the lr parameter is set , if not add it */ - osip_uri_uparam_get_byname(rt->url, "lr", &lr_param); - if (lr_param==NULL){ - char *tmproute; - osip_uri_uparam_add(rt->url,osip_strdup("lr"),NULL); - osip_route_to_str(rt,&tmproute); - sal_op_set_route(op,tmproute); - osip_free(tmproute); - } - } - osip_route_free(rt); - } -} - -SalOp * sal_op_new(Sal *sal){ - SalOp *op=ms_new0(SalOp,1); - __sal_op_init(op,sal); - op->cid=op->did=op->tid=op->rid=op->nid=op->sid=-1; - op->result=NULL; - op->supports_session_timers=FALSE; - op->sdp_offering=TRUE; - op->pending_auth=NULL; - op->sdp_answer=NULL; - op->reinvite=FALSE; - op->call_id=NULL; - op->replaces=NULL; - op->referred_by=NULL; - op->masquerade_via=FALSE; - op->auto_answer_asked=FALSE; - op->auth_info=NULL; - op->terminated=FALSE; - return op; -} - -bool_t sal_call_autoanswer_asked(SalOp *op) -{ - return op->auto_answer_asked; -} - -void sal_op_release(SalOp *op){ - if (op->sdp_answer) - sdp_message_free(op->sdp_answer); - if (op->pending_auth) - eXosip_event_free(op->pending_auth); - if (op->rid!=-1){ - sal_remove_register(op->base.root,op->rid); - eXosip_register_remove(op->rid); - } - if (op->cid!=-1){ - ms_message("Cleaning cid %i",op->cid); - sal_remove_call(op->base.root,op); - } - if (op->sid!=-1){ - sal_remove_out_subscribe(op->base.root,op); - } - if (op->nid!=-1){ - sal_remove_in_subscribe(op->base.root,op); - if (op->call_id) - osip_call_id_free(op->call_id); - op->call_id=NULL; - } - if (op->pending_auth){ - sal_remove_pending_auth(op->base.root,op); - } - if (op->result) - sal_media_description_unref(op->result); - if (op->call_id){ - sal_remove_other(op->base.root,op); - osip_call_id_free(op->call_id); - } - if (op->replaces){ - ms_free(op->replaces); - } - if (op->referred_by){ - ms_free(op->referred_by); - } - if (op->auth_info) { - sal_auth_info_delete(op->auth_info); - } - __sal_op_free(op); -} - -static void _osip_trace_func(char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap){ - int ortp_level=ORTP_DEBUG; - switch(level){ - case OSIP_INFO1: - case OSIP_INFO2: - case OSIP_INFO3: - case OSIP_INFO4: - ortp_level=ORTP_MESSAGE; - break; - case OSIP_WARNING: - ortp_level=ORTP_WARNING; - break; - case OSIP_ERROR: - case OSIP_BUG: - ortp_level=ORTP_ERROR; - break; - case OSIP_FATAL: - ortp_level=ORTP_FATAL; - break; - case END_TRACE_LEVEL: - break; - } - if (ortp_log_level_enabled(level)){ - int len=strlen(chfr); - char *chfrdup=ortp_strdup(chfr); - /*need to remove endline*/ - if (len>1){ - if (chfrdup[len-1]=='\n') - chfrdup[len-1]='\0'; - if (chfrdup[len-2]=='\r') - chfrdup[len-2]='\0'; - } - ortp_logv(ortp_level,chfrdup,ap); - ortp_free(chfrdup); - } -} - - -Sal * sal_init(){ - static bool_t firsttime=TRUE; - Sal *sal; - if (firsttime){ - osip_trace_initialize_func (OSIP_INFO4,&_osip_trace_func); - firsttime=FALSE; - } - eXosip_init(); - sal=ms_new0(Sal,1); - sal->keepalive_period=30; - sal->double_reg=TRUE; - sal->use_rports=TRUE; - sal->use_101=TRUE; - sal->reuse_authorization=FALSE; - sal->rootCa = 0; - sal->verify_server_certs=TRUE; - sal->verify_server_cn=TRUE; - sal->expire_old_contact=FALSE; - sal->add_dates=FALSE; - sal->dscp=-1; - return sal; -} - -void sal_uninit(Sal* sal){ - eXosip_quit(); - if (sal->rootCa) - ms_free(sal->rootCa); - ms_free(sal); -} - -void sal_set_user_pointer(Sal *sal, void *user_data){ - sal->up=user_data; -} - -void *sal_get_user_pointer(const Sal *sal){ - return sal->up; -} - -static void unimplemented_stub(){ - ms_warning("Unimplemented SAL callback"); -} - -void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ - memcpy(&ctx->callbacks,cbs,sizeof(*cbs)); - if (ctx->callbacks.call_received==NULL) - ctx->callbacks.call_received=(SalOnCallReceived)unimplemented_stub; - if (ctx->callbacks.call_ringing==NULL) - ctx->callbacks.call_ringing=(SalOnCallRinging)unimplemented_stub; - if (ctx->callbacks.call_accepted==NULL) - ctx->callbacks.call_accepted=(SalOnCallAccepted)unimplemented_stub; - if (ctx->callbacks.call_failure==NULL) - ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub; - if (ctx->callbacks.call_terminated==NULL) - ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub; - if (ctx->callbacks.call_released==NULL) - ctx->callbacks.call_released=(SalOnCallReleased)unimplemented_stub; - if (ctx->callbacks.call_updating==NULL) - ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub; - if (ctx->callbacks.auth_requested==NULL) - ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub; - if (ctx->callbacks.auth_success==NULL) - ctx->callbacks.auth_success=(SalOnAuthSuccess)unimplemented_stub; - if (ctx->callbacks.register_success==NULL) - ctx->callbacks.register_success=(SalOnRegisterSuccess)unimplemented_stub; - if (ctx->callbacks.register_failure==NULL) - ctx->callbacks.register_failure=(SalOnRegisterFailure)unimplemented_stub; - if (ctx->callbacks.dtmf_received==NULL) - ctx->callbacks.dtmf_received=(SalOnDtmfReceived)unimplemented_stub; - if (ctx->callbacks.notify==NULL) - ctx->callbacks.notify=(SalOnNotify)unimplemented_stub; - if (ctx->callbacks.notify_presence==NULL) - ctx->callbacks.notify_presence=(SalOnNotifyPresence)unimplemented_stub; - if (ctx->callbacks.subscribe_received==NULL) - ctx->callbacks.subscribe_received=(SalOnSubscribeReceived)unimplemented_stub; - if (ctx->callbacks.text_received==NULL) - ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; - if (ctx->callbacks.ping_reply==NULL) - ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; -} - -int sal_unlisten_ports(Sal *ctx){ - if (ctx->running){ - eXosip_quit(); - eXosip_init(); - ctx->running=FALSE; - } - return 0; -} - -int sal_reset_transports(Sal *ctx){ -#ifdef HAVE_EXOSIP_RESET_TRANSPORTS - if (ctx->running){ - ms_message("Exosip transports reset."); - eXosip_reset_transports(); - } - return 0; -#else - ms_warning("sal_reset_transports() not implemented in this version."); - return -1; -#endif -} - - -static void set_tls_options(Sal *ctx){ - if (ctx->rootCa) { - eXosip_tls_ctx_t tlsCtx; - memset(&tlsCtx, 0, sizeof(tlsCtx)); - snprintf(tlsCtx.root_ca_cert, sizeof(tlsCtx.client.cert), "%s", ctx->rootCa); - eXosip_set_tls_ctx(&tlsCtx); - } -#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE - eXosip_tls_verify_certificate(ctx->verify_server_certs); -#endif -#ifdef HAVE_EXOSIP_TLS_VERIFY_CN - eXosip_tls_verify_cn(ctx->verify_server_cn); -#endif -} - -void sal_set_dscp(Sal *ctx, int dscp){ - ctx->dscp=dscp; -#ifdef HAVE_EXOSIP_DSCP - if (dscp!=-1) - eXosip_set_option(EXOSIP_OPT_SET_DSCP,&ctx->dscp); -#endif -} - -int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure){ - int err; - bool_t ipv6; - int proto=IPPROTO_UDP; - int keepalive = ctx->keepalive_period; - - ctx->transport = tr; - switch (tr) { - case SalTransportUDP: - proto=IPPROTO_UDP; - eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &keepalive); - break; - case SalTransportTCP: - case SalTransportTLS: - proto= IPPROTO_TCP; - if (!ctx->tcp_tls_keepalive) keepalive=-1; - eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE,&keepalive); - set_tls_options(ctx); - break; - default: - ms_warning("unexpected proto, using datagram"); - } - /*see if it looks like an IPv6 address*/ - int use_rports = ctx->use_rports; // Copy char to int to avoid bad alignment - eXosip_set_option(EXOSIP_OPT_USE_RPORT,&use_rports); - int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment - eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101); - sal_set_dscp(ctx,ctx->dscp); - sal_use_dates(ctx,ctx->add_dates); - - ipv6=strchr(addr,':')!=NULL; - eXosip_enable_ipv6(ipv6); - - if (is_secure && tr == SalTransportUDP){ - ms_fatal("SIP over DTLS is not supported yet."); - return -1; - } - err=eXosip_listen_addr(proto, addr, port, ipv6 ? PF_INET6 : PF_INET, is_secure); - ctx->running=TRUE; - return err; -} - -ortp_socket_t sal_get_socket(Sal *ctx){ -#ifdef HAVE_EXOSIP_GET_SOCKET - return eXosip_get_socket(IPPROTO_UDP); -#else - ms_warning("Sorry, eXosip does not have eXosip_get_socket() method"); - return -1; -#endif -} - -void sal_set_user_agent(Sal *ctx, const char *user_agent){ - eXosip_set_user_agent(user_agent); -} - -void sal_use_session_timers(Sal *ctx, int expires){ - ctx->session_expires=expires; -} - -void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){ - ctx->one_matching_codec=one_matching_codec; -} - -MSList *sal_get_pending_auths(Sal *sal){ - return ms_list_copy(sal->pending_auths); -} - -void sal_use_double_registrations(Sal *ctx, bool_t enabled){ - ctx->double_reg=enabled; -} - -void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ - ctx->expire_old_contact=enabled; -} - -void sal_use_dates(Sal *ctx, bool_t enabled){ - ctx->add_dates=enabled; -#ifdef EXOSIP_OPT_REGISTER_WITH_DATE - { - int tmp=enabled; - eXosip_set_option(EXOSIP_OPT_REGISTER_WITH_DATE,&tmp); - } -#else - if (enabled) ms_warning("Exosip does not support EXOSIP_OPT_REGISTER_WITH_DATE option."); -#endif -} - -void sal_use_rport(Sal *ctx, bool_t use_rports){ - ctx->use_rports=use_rports; -} -void sal_use_101(Sal *ctx, bool_t use_101){ - ctx->use_101=use_101; -} - -void sal_set_root_ca(Sal* ctx, const char* rootCa) { - if (ctx->rootCa) - ms_free(ctx->rootCa); - ctx->rootCa = ms_strdup(rootCa); - set_tls_options(ctx); -} - -const char *sal_get_root_ca(Sal* ctx) { - return ctx->rootCa; -} - -void sal_verify_server_certificates(Sal *ctx, bool_t verify){ - ctx->verify_server_certs=verify; -#ifdef HAVE_EXOSIP_TLS_VERIFY_CERTIFICATE - eXosip_tls_verify_certificate(verify); -#endif -} - -void sal_verify_server_cn(Sal *ctx, bool_t verify){ - ctx->verify_server_cn=verify; -#ifdef HAVE_EXOSIP_TLS_VERIFY_CN - eXosip_tls_verify_cn(verify); -#endif -} - -static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval,SalTransport* transport){ - osip_via_t *via=NULL; - osip_generic_param_t *param=NULL; - const char *rport=NULL; - - *rportval=5060; - *received=NULL; - osip_message_get_via(msg,0,&via); - if (!via) { - ms_warning("extract_received_rport(): no via."); - return -1; - } - - *transport = sal_transport_parse(via->protocol); - - if (via->port && via->port[0]!='\0') - *rportval=atoi(via->port); - - osip_via_param_get_byname(via,"rport",¶m); - if (param) { - rport=param->gvalue; - if (rport && rport[0]!='\0') *rportval=atoi(rport); - *received=via->host; - } - param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param) *received=param->gvalue; - - if (rport==NULL && *received==NULL){ - ms_warning("extract_received_rport(): no rport and no received parameters."); - return -1; - } - return 0; -} - -static void set_sdp(osip_message_t *sip,sdp_message_t *msg){ - int sdplen; - char clen[10]; - char *sdp=NULL; - sdp_message_to_str(msg,&sdp); - sdplen=strlen(sdp); - snprintf(clen,sizeof(clen),"%i",sdplen); - osip_message_set_body(sip,sdp,sdplen); - osip_message_set_content_type(sip,"application/sdp"); - osip_message_set_content_length(sip,clen); - osip_free(sdp); -} - -static void set_sdp_from_desc(osip_message_t *sip, const SalMediaDescription *desc){ - sdp_message_t *msg=media_description_to_sdp(desc); - if (msg==NULL) { - ms_error("Fail to print sdp message !"); - return; - } - set_sdp(sip,msg); - sdp_message_free(msg); -} - -static void sdp_process(SalOp *h){ - ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); - if (h->result){ - sal_media_description_unref(h->result); - } - h->result=sal_media_description_new(); - if (h->sdp_offering){ - offer_answer_initiate_outgoing(h->base.local_media,h->base.remote_media,h->result); - }else{ - int i; - if (h->sdp_answer){ - sdp_message_free(h->sdp_answer); - } - offer_answer_initiate_incoming(h->base.local_media,h->base.remote_media,h->result,h->base.root->one_matching_codec); - h->sdp_answer=media_description_to_sdp(h->result); - /*once we have generated the SDP answer, we modify the result description for processing by the upper layer. - It should contains media parameters constraint from the remote offer, not our response*/ - strcpy(h->result->addr,h->base.remote_media->addr); - h->result->bandwidth=h->base.remote_media->bandwidth; - - for(i=0;iresult->n_active_streams;++i){ - strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); - strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); - h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; - h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; - h->result->streams[i].rtp_port=h->base.remote_media->streams[i].rtp_port; - h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; - if (h->result->streams[i].proto == SalProtoRtpSavp) { - h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; - } - } - } - -} - -int sal_call_is_offerer(const SalOp *h){ - return h->sdp_offering; -} - -int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ - if (desc) - sal_media_description_ref(desc); - if (h->base.local_media) - sal_media_description_unref(h->base.local_media); - h->base.local_media=desc; - if (h->base.remote_media){ - /*case of an incoming call where we modify the local capabilities between the time - * the call is ringing and it is accepted (for example if you want to accept without video*/ - /*reset the sdp answer so that it is computed again*/ - if (h->sdp_answer){ - sdp_message_free(h->sdp_answer); - h->sdp_answer=NULL; - } - } - return 0; -} - -int sal_call(SalOp *h, const char *from, const char *to){ - int err; - const char *route; - osip_message_t *invite=NULL; - osip_call_id_t *callid; - sal_op_set_from(h,from); - sal_op_set_to(h,to); - sal_exosip_fix_route(h); - - h->terminated = FALSE; - - route = sal_op_get_route(h); - err=eXosip_call_build_initial_invite(&invite,to,from,route,"Phone call"); - if (err!=0){ - ms_error("Could not create call. Error %d (from=%s to=%s route=%s)", - err, from, to, route); - return -1; - } - osip_message_set_allow(invite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); - if (h->base.contact){ - _osip_list_set_empty(&invite->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(invite,h->base.contact); - } - if (h->base.root->session_expires!=0){ - osip_message_set_header(invite, "Session-expires", "200"); - osip_message_set_supported(invite, "timer"); - } - sal_exosip_add_custom_headers(invite,h->base.custom_headers); - if (h->base.local_media){ - h->sdp_offering=TRUE; - set_sdp_from_desc(invite,h->base.local_media); - }else h->sdp_offering=FALSE; - if (h->replaces){ - osip_message_set_header(invite,"Replaces",h->replaces); - if (h->referred_by) - osip_message_set_header(invite,"Referred-By",h->referred_by); - } - - eXosip_lock(); - err=eXosip_call_send_initial_invite(invite); - eXosip_unlock(); - h->cid=err; - if (err<0){ - ms_error("Fail to send invite ! Error code %d", err); - return -1; - }else{ - char *tmp=NULL; - callid=osip_message_get_call_id(invite); - osip_call_id_to_str(callid,&tmp); - h->base.call_id=ms_strdup(tmp); - osip_free(tmp); - sal_add_call(h->base.root,h); - } - return 0; -} - -int sal_call_notify_ringing(SalOp *h, bool_t early_media){ - osip_message_t *msg; - - /*if early media send also 180 and 183 */ - if (early_media){ - msg=NULL; - eXosip_lock(); - eXosip_call_build_answer(h->tid,183,&msg); - if (msg){ - sdp_process(h); - if (h->sdp_answer){ - set_sdp(msg,h->sdp_answer); - sdp_message_free(h->sdp_answer); - h->sdp_answer=NULL; - } - eXosip_call_send_answer(h->tid,183,msg); - } - eXosip_unlock(); - }else{ - eXosip_lock(); - eXosip_call_send_answer(h->tid,180,NULL); - eXosip_unlock(); - } - return 0; -} - -int sal_call_accept(SalOp * h){ - osip_message_t *msg; - const char *contact=sal_op_get_contact(h); - /* sends a 200 OK */ - int err=eXosip_call_build_answer(h->tid,200,&msg); - if (err<0 || msg==NULL){ - ms_error("Fail to build answer for call: err=%i",err); - return -1; - } - if (h->base.root->session_expires!=0){ - if (h->supports_session_timers) osip_message_set_supported(msg, "timer"); - } - - if (contact) { - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,contact); - } - - if (h->base.local_media){ - /*this is the case where we received an invite without SDP*/ - if (h->sdp_offering) { - set_sdp_from_desc(msg,h->base.local_media); - }else{ - if (h->sdp_answer==NULL) sdp_process(h); - if (h->sdp_answer){ - set_sdp(msg,h->sdp_answer); - sdp_message_free(h->sdp_answer); - h->sdp_answer=NULL; - } - } - }else{ - ms_error("You are accepting a call but not defined any media capabilities !"); - } - eXosip_call_send_answer(h->tid,200,msg); - return 0; -} - -int sal_call_decline(SalOp *h, SalReason reason, const char *redirect){ - if (reason==SalReasonBusy){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,486,NULL); - eXosip_unlock(); - } - else if (reason==SalReasonTemporarilyUnavailable){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,480,NULL); - eXosip_unlock(); - }else if (reason==SalReasonDoNotDisturb){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,600,NULL); - eXosip_unlock(); - }else if (reason==SalReasonMedia){ - eXosip_lock(); - eXosip_call_send_answer(h->tid,415,NULL); - eXosip_unlock(); - }else if (redirect!=NULL && reason==SalReasonRedirect){ - osip_message_t *msg; - int code; - if (strstr(redirect,"sip:")!=0) code=302; - else code=380; - eXosip_lock(); - eXosip_call_build_answer(h->tid,code,&msg); - osip_message_set_contact(msg,redirect); - eXosip_call_send_answer(h->tid,code,msg); - eXosip_unlock(); - }else sal_call_terminate(h); - return 0; -} - -SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ - return h->base.remote_media; -} - -SalMediaDescription * sal_call_get_final_media_description(SalOp *h){ - if (h->base.local_media && h->base.remote_media && !h->result){ - sdp_process(h); - } - return h->result; -} - -int sal_call_set_referer(SalOp *h, SalOp *refered_call){ - if (refered_call->replaces) - h->replaces=ms_strdup(refered_call->replaces); - if (refered_call->referred_by) - h->referred_by=ms_strdup(refered_call->referred_by); - return 0; -} - -static int send_notify_for_refer(int did, const char *sipfrag){ - osip_message_t *msg; - eXosip_lock(); - eXosip_call_build_notify(did,EXOSIP_SUBCRSTATE_ACTIVE,&msg); - if (msg==NULL){ - eXosip_unlock(); - ms_warning("Could not build NOTIFY for refer."); - return -1; - } - osip_message_set_content_type(msg,"message/sipfrag"); - osip_message_set_header(msg,"Event","refer"); - osip_message_set_body(msg,sipfrag,strlen(sipfrag)); - eXosip_call_send_request(did,msg); - eXosip_unlock(); - return 0; -} - -/* currently only support to notify trying and 200Ok*/ -int sal_call_notify_refer_state(SalOp *h, SalOp *newcall){ - if (newcall==NULL){ - /* in progress*/ - send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n"); - } - else if (newcall->cid!=-1){ - if (newcall->did==-1){ - /* not yet established*/ - if (!newcall->terminated){ - /* in progress*/ - send_notify_for_refer(h->did,"SIP/2.0 100 Trying\r\n"); - } - }else{ - if (!newcall->terminated){ - if (send_notify_for_refer(h->did,"SIP/2.0 200 Ok\r\n")==-1){ - /* we need previous notify transaction to complete, so buffer the request for later*/ - h->sipfrag_pending="SIP/2.0 200 Ok\r\n"; - } - } - } - } - return 0; -} - -int sal_ping(SalOp *op, const char *from, const char *to){ - osip_message_t *options=NULL; - - sal_op_set_from(op,from); - sal_op_set_to(op,to); - sal_exosip_fix_route(op); - - eXosip_options_build_request (&options, sal_op_get_to(op), - sal_op_get_from(op),sal_op_get_route(op)); - if (options){ - if (op->base.root->session_expires!=0){ - osip_message_set_header(options, "Session-expires", "200"); - osip_message_set_supported(options, "timer"); - } - sal_add_other(sal_op_get_sal(op),op,options); - return eXosip_options_send_request(options); - } - return -1; -} - -int sal_call_refer(SalOp *h, const char *refer_to){ - osip_message_t *msg=NULL; - int err=0; - eXosip_lock(); - eXosip_call_build_refer(h->did,refer_to, &msg); - if (msg) err=eXosip_call_send_request(h->did, msg); - else err=-1; - eXosip_unlock(); - return err; -} - -int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ - osip_message_t *msg=NULL; - char referto[256]={0}; - int err=0; - eXosip_lock(); - if (eXosip_call_get_referto(other_call_h->did,referto,sizeof(referto)-1)!=0){ - ms_error("eXosip_call_get_referto() failed for did=%i",other_call_h->did); - eXosip_unlock(); - return -1; - } - eXosip_call_build_refer(h->did,referto, &msg); - osip_message_set_header(msg,"Referred-By",h->base.from); - if (msg) err=eXosip_call_send_request(h->did, msg); - else err=-1; - eXosip_unlock(); - return err; -} - -SalOp *sal_call_get_replaces(SalOp *h){ - if (h!=NULL && h->replaces!=NULL){ - int cid; - eXosip_lock(); - cid=eXosip_call_find_by_replaces(h->replaces); - eXosip_unlock(); - if (cid>0){ - SalOp *ret=sal_find_call(h->base.root,cid); - return ret; - } - } - return NULL; -} - -int sal_call_send_dtmf(SalOp *h, char dtmf){ - osip_message_t *msg=NULL; - char dtmf_body[128]; - char clen[10]; - - eXosip_lock(); - eXosip_call_build_info(h->did,&msg); - if (msg){ - snprintf(dtmf_body, sizeof(dtmf_body), "Signal=%c\r\nDuration=250\r\n", dtmf); - osip_message_set_body(msg,dtmf_body,strlen(dtmf_body)); - osip_message_set_content_type(msg,"application/dtmf-relay"); - snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(dtmf_body)); - osip_message_set_content_length(msg,clen); - eXosip_call_send_request(h->did,msg); - } - eXosip_unlock(); - return 0; -} - -static void push_auth_to_exosip(const SalAuthInfo *info){ - const char *userid; - if (info->userid==NULL || info->userid[0]=='\0') userid=info->username; - else userid=info->userid; - ms_message("Authentication info for username [%s], id[%s], realm [%s] added to eXosip", info->username,userid, info->realm); - eXosip_add_authentication_info (info->username,userid, - info->password, NULL,info->realm); -} -/* - * Just for symmetry ;-) - */ -static void pop_auth_from_exosip() { - eXosip_clear_authentication_info(); -} - -int sal_call_terminate(SalOp *h){ - int err; - if (h == NULL) return -1; - if (h->auth_info) push_auth_to_exosip(h->auth_info); - eXosip_lock(); - err=eXosip_call_terminate(h->cid,h->did); - eXosip_unlock(); - if (!h->base.root->reuse_authorization) pop_auth_from_exosip(); - if (err!=0){ - ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did); - } - h->terminated=TRUE; - return 0; -} - -void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ - bool_t terminating=FALSE; - if (h->pending_auth && strcmp(h->pending_auth->request->sip_method,"BYE")==0) { - terminating=TRUE; - } - if (h->terminated && !terminating) return; - - if (h->pending_auth){ - push_auth_to_exosip(info); - - /*FIXME exosip does not take into account this update register message*/ - /* - if (fix_message_contact(h, h->pending_auth->request,h->pending_auth->response)) { - - }; - */ - update_contact_from_response(h,h->pending_auth->response); - eXosip_lock(); - eXosip_default_action(h->pending_auth); - eXosip_unlock(); - ms_message("eXosip_default_action() done"); - if (!h->base.root->reuse_authorization) pop_auth_from_exosip(); - - if (h->auth_info) sal_auth_info_delete(h->auth_info); /*if already exist*/ - h->auth_info=sal_auth_info_clone(info); /*store auth info for subsequent request*/ - } -} -void sal_op_cancel_authentication(SalOp *h) { - if (h->rid >0) { - sal_op_get_sal(h)->callbacks.register_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure"); - } else if (h->cid >0) { - sal_op_get_sal(h)->callbacks.call_failure(h,SalErrorFailure, SalReasonForbidden,"Authentication failure",0); - } else { - ms_warning("Auth failure not handled"); - } - -} -static void set_network_origin(SalOp *op, osip_message_t *req){ - const char *received=NULL; - int rport=5060; - char origin[64]={0}; - SalTransport transport; - if (extract_received_rport(req,&received,&rport,&transport)!=0){ - osip_via_t *via=NULL; - char *tmp; - osip_message_get_via(req,0,&via); - received=osip_via_get_host(via); - tmp=osip_via_get_port(via); - if (tmp) rport=atoi(tmp); - } - if (transport != SalTransportUDP) { - snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport); - } else { - snprintf(origin,sizeof(origin)-1,"sip:%s:%i;transport=%s",received,rport,sal_transport_to_string(transport)); - } - __sal_op_set_network_origin(op,origin); -} - -static void set_remote_ua(SalOp* op, osip_message_t *req){ - if (op->base.remote_ua==NULL){ - osip_header_t *h=NULL; - osip_message_get_user_agent(req,0,&h); - if (h){ - op->base.remote_ua=ms_strdup(h->hvalue); - } - } -} - -static void set_remote_contact(SalOp* op, osip_message_t *req){ - if (op->base.remote_contact==NULL){ - osip_contact_t *h=NULL; - osip_message_get_contact(req,0,&h); - if (h){ - char *tmp=NULL; - osip_contact_to_str(h,&tmp); - __sal_op_set_remote_contact(op,tmp); - osip_free(tmp); - } - } -} - -static void set_replaces(SalOp *op, osip_message_t *req){ - osip_header_t *h=NULL; - - if (op->replaces){ - ms_free(op->replaces); - op->replaces=NULL; - } - osip_message_header_get_byname(req,"replaces",0,&h); - if (h){ - if (h->hvalue && h->hvalue[0]!='\0'){ - op->replaces=ms_strdup(h->hvalue); - } - } -} - -static SalOp *find_op(Sal *sal, eXosip_event_t *ev){ - if (ev->cid>0){ - return sal_find_call(sal,ev->cid); - } - if (ev->rid>0){ - return sal_find_register(sal,ev->rid); - } - if (ev->sid>0){ - return sal_find_out_subscribe(sal,ev->sid); - } - if (ev->nid>0){ - return sal_find_in_subscribe(sal,ev->nid); - } - if (ev->response) return sal_find_other(sal,ev->response); - else if (ev->request) return sal_find_other(sal,ev->request); - return NULL; -} - -static void inc_new_call(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_op_new(sal); - osip_from_t *from,*to; - osip_call_info_t *call_info; - char *tmp=NULL; - sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); - - osip_call_id_t *callid=osip_message_get_call_id(ev->request); - - osip_call_id_to_str(callid,&tmp); - op->base.call_id=ms_strdup(tmp); - osip_free(tmp); - - set_network_origin(op,ev->request); - set_remote_contact(op,ev->request); - set_remote_ua(op,ev->request); - set_replaces(op,ev->request); - sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request)); - - if (sdp){ - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - }else op->sdp_offering=TRUE; - - from=osip_message_get_from(ev->request); - to=osip_message_get_to(ev->request); - osip_from_to_str(from,&tmp); - sal_op_set_from(op,tmp); - osip_free(tmp); - osip_from_to_str(to,&tmp); - sal_op_set_to(op,tmp); - osip_free(tmp); - - osip_message_get_call_info(ev->request,0,&call_info); - if(call_info) - { - osip_call_info_to_str(call_info,&tmp); - if( strstr(tmp,"answer-after=") != NULL) - { - op->auto_answer_asked=TRUE; - ms_message("The caller asked to automatically answer the call(Emergency?)\n"); - } - osip_free(tmp); - } - - op->tid=ev->tid; - op->cid=ev->cid; - op->did=ev->did; - sal_add_call(op->base.root,op); - sal->callbacks.call_received(op); -} - -static void handle_reinvite(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - sdp_message_t *sdp; - - if (op==NULL) { - ms_warning("Reinvite for non-existing operation !"); - return; - } - op->reinvite=TRUE; - op->tid=ev->tid; - sdp=eXosip_get_sdp_info(ev->request); - 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; - } - if (sdp){ - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - - }else { - op->sdp_offering=TRUE; - } - sal->callbacks.call_updating(op); -} - -static void handle_ack(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - sdp_message_t *sdp; - - if (op==NULL) { - ms_warning("ack for non-existing call !"); - return; - } - if (op->terminated) { - ms_warning("ack for terminated call, ignoring"); - return; - } - - if (op->sdp_offering){ - sdp=eXosip_get_sdp_info(ev->ack); - 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); - sdp_message_free(sdp); - } - } - if (op->reinvite){ - op->reinvite=FALSE; - } - sal->callbacks.call_ack(op); -} - -static void update_contact_from_response(SalOp *op, osip_message_t *response){ - const char *received; - int rport; - SalTransport transport; - if (extract_received_rport(response,&received,&rport,&transport)==0){ - const char *contact=sal_op_get_contact(op); - if (!contact){ - /*no contact given yet, use from instead*/ - contact=sal_op_get_from(op); - } - if (contact){ - SalAddress *addr=sal_address_new(contact); - char *tmp; - sal_address_set_domain(addr,received); - sal_address_set_port_int(addr,rport); - if (transport!=SalTransportUDP) - sal_address_set_transport(addr,transport); - tmp=sal_address_as_string(addr); - ms_message("Contact address updated to %s",tmp); - sal_op_set_contact(op,tmp); - sal_address_destroy(addr); - ms_free(tmp); - } - } -} - -static int call_proceeding(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - - if (op==NULL || op->terminated==TRUE) { - ms_warning("This call has been canceled."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return -1; - } - if (ev->did>0) - op->did=ev->did; - op->tid=ev->tid; - - /* update contact if received and rport are set by the server - note: will only be used by remote for next INVITE, if any...*/ - update_contact_from_response(op,ev->response); - return 0; -} - -static void call_ringing(Sal *sal, eXosip_event_t *ev){ - sdp_message_t *sdp; - SalOp *op=find_op(sal,ev); - if (call_proceeding(sal, ev)==-1) return; - - set_remote_ua(op,ev->response); - sdp=eXosip_get_sdp_info(ev->response); - if (sdp){ - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - if (op->base.local_media) sdp_process(op); - } - sal->callbacks.call_ringing(op); -} - -static void call_accepted(Sal *sal, eXosip_event_t *ev){ - sdp_message_t *sdp; - osip_message_t *msg=NULL; - SalOp *op=find_op(sal,ev); - const char *contact; - - if (op==NULL || op->terminated==TRUE) { - ms_warning("This call has been already terminated."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return ; - } - - op->did=ev->did; - set_remote_ua(op,ev->response); - set_remote_contact(op,ev->response); - - sdp=eXosip_get_sdp_info(ev->response); - if (sdp){ - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - sdp_message_free(sdp); - if (op->base.local_media) sdp_process(op); - } - eXosip_call_build_ack(ev->did,&msg); - if (msg==NULL) { - ms_warning("This call has been already terminated."); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return ; - } - contact=sal_op_get_contact(op); - if (contact) { - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,contact); - } - if (op->sdp_answer){ - set_sdp(msg,op->sdp_answer); - sdp_message_free(op->sdp_answer); - op->sdp_answer=NULL; - } - eXosip_call_send_ack(ev->did,msg); - sal->callbacks.call_accepted(op); -} - -static void call_terminated(Sal *sal, eXosip_event_t *ev){ - char *from=NULL; - SalOp *op=find_op(sal,ev); - if (op==NULL){ - ms_warning("Call terminated for already closed call ?"); - return; - } - if (ev->request){ - osip_from_to_str(ev->request->from,&from); - } - sal->callbacks.call_terminated(op,from!=NULL ? from : sal_op_get_from(op)); - if (from) osip_free(from); - op->terminated=TRUE; -} - -static void call_released(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - if (op==NULL){ - ms_warning("No op associated to this call_released()"); - return; - } - if (!op->terminated){ - /* no response received so far */ - call_failure(sal,ev); - } - sal->callbacks.call_released(op); -} - -static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){ - const char *prx_realm=NULL,*www_realm=NULL; - osip_proxy_authenticate_t *prx_auth; - osip_www_authenticate_t *www_auth; - - *username=osip_uri_get_username(resp->from->url); - prx_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->proxy_authenticates,0); - www_auth=(osip_proxy_authenticate_t*)osip_list_get(&resp->www_authenticates,0); - if (prx_auth!=NULL) - prx_realm=osip_proxy_authenticate_get_realm(prx_auth); - if (www_auth!=NULL) - www_realm=osip_www_authenticate_get_realm(www_auth); - - if (prx_realm){ - *realm=prx_realm; - }else if (www_realm){ - *realm=www_realm; - }else{ - return -1; - } - return 0; -} - -static int get_auth_data_from_request(osip_message_t *msg, const char **realm, const char **username){ - osip_authorization_t *auth=NULL; - osip_proxy_authorization_t *prx_auth=NULL; - - *username=osip_uri_get_username(msg->from->url); - osip_message_get_authorization(msg, 0, &auth); - if (auth){ - *realm=osip_authorization_get_realm(auth); - return 0; - } - osip_message_get_proxy_authorization(msg,0,&prx_auth); - if (prx_auth){ - *realm=osip_proxy_authorization_get_realm(prx_auth); - return 0; - } - return -1; -} - -static int get_auth_data(eXosip_event_t *ev, const char **realm, const char **username){ - if (ev->response && get_auth_data_from_response(ev->response,realm,username)==0) return 0; - if (ev->request && get_auth_data_from_request(ev->request,realm,username)==0) return 0; - return -1; -} - -int sal_op_get_auth_requested(SalOp *op, const char **realm, const char **username){ - if (op->pending_auth){ - return get_auth_data(op->pending_auth,realm,username); - } - return -1; -} - -static bool_t process_authentication(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - const char *username,*realm; - op=find_op(sal,ev); - if (op==NULL){ - ms_warning("No operation associated with this authentication !"); - return TRUE; - } - if (get_auth_data(ev,&realm,&username)==0){ - if (op->pending_auth!=NULL){ - eXosip_event_free(op->pending_auth); - op->pending_auth=ev; - }else{ - op->pending_auth=ev; - sal_add_pending_auth(sal,op); - } - - sal->callbacks.auth_requested(op,realm,username); - return FALSE; - } - return TRUE; -} - -static void authentication_ok(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - const char *username,*realm; - op=find_op(sal,ev); - if (op==NULL){ - ms_warning("No operation associated with this authentication_ok!"); - return ; - } - if (op->pending_auth){ - eXosip_event_free(op->pending_auth); - sal_remove_pending_auth(sal,op); - op->pending_auth=NULL; - } - if (get_auth_data(ev,&realm,&username)==0){ - sal->callbacks.auth_success(op,realm,username); - } -} - -static bool_t call_failure(Sal *sal, eXosip_event_t *ev){ - SalOp *op; - int code=0; - char* computedReason=NULL; - const char *reason=NULL; - SalError error=SalErrorUnknown; - SalReason sr=SalReasonUnknown; - - - op=(SalOp*)find_op(sal,ev); - - if (op==NULL) { - ms_warning("Call failure reported for a closed call, ignored."); - return TRUE; - } - - if (ev->response){ - code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - osip_header_t *h=NULL; - if (!osip_message_header_get_byname( ev->response - ,"Reason" - ,0 - ,&h)) { - computedReason = ms_strdup_printf("%s %s",reason,osip_header_get_value(h)); - reason = computedReason; - - } - } - switch(code) - { - case 401: - case 407: - return process_authentication(sal,ev); - break; - case 400: - error=SalErrorUnknown; - break; - case 404: - error=SalErrorFailure; - sr=SalReasonNotFound; - break; - case 415: - error=SalErrorFailure; - sr=SalReasonMedia; - break; - case 422: - eXosip_default_action(ev); - return TRUE; - break; - case 480: - error=SalErrorFailure; - sr=SalReasonTemporarilyUnavailable; - break; - case 486: - error=SalErrorFailure; - sr=SalReasonBusy; - break; - case 487: - break; - case 600: - error=SalErrorFailure; - sr=SalReasonDoNotDisturb; - break; - case 603: - error=SalErrorFailure; - sr=SalReasonDeclined; - break; - default: - if (code>0){ - error=SalErrorFailure; - sr=SalReasonUnknown; - }else error=SalErrorNoResponse; - } - op->terminated=TRUE; - sal->callbacks.call_failure(op,error,sr,reason,code); - if (computedReason != NULL){ - ms_free(computedReason); - } - return TRUE; -} - -/* Request remote side to send us VFU */ -void sal_call_send_vfu_request(SalOp *h){ - osip_message_t *msg=NULL; - char info_body[] = - "" - "" - " " - " " - " " - " " - " " - ""; - - char clen[10]; - - eXosip_lock(); - eXosip_call_build_info(h->did,&msg); - if (msg){ - osip_message_set_body(msg,info_body,strlen(info_body)); - osip_message_set_content_type(msg,"application/media_control+xml"); - snprintf(clen,sizeof(clen),"%lu",(unsigned long)strlen(info_body)); - osip_message_set_content_length(msg,clen); - eXosip_call_send_request(h->did,msg); - ms_message("Sending VFU request !"); - } - eXosip_unlock(); -} - -static void process_media_control_xml(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - osip_body_t *body=NULL; - - if (op==NULL){ - ms_warning("media control xml received without operation context!"); - return ; - } - - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL && - strstr(body->body,"picture_fast_update")){ - osip_message_t *ans=NULL; - ms_message("Receiving VFU request !"); - if (sal->callbacks.vfu_request){ - sal->callbacks.vfu_request(op); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - return; - } - } - /*in all other cases we must say it is not implemented.*/ - { - osip_message_t *ans=NULL; - eXosip_lock(); - eXosip_call_build_answer(ev->tid,501,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,501,ans); - eXosip_unlock(); - } -} - -static void process_dtmf_relay(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - osip_body_t *body=NULL; - - if (op==NULL){ - ms_warning("media dtmf relay received without operation context!"); - return ; - } - - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL){ - osip_message_t *ans=NULL; - const char *name=strstr(body->body,"Signal"); - if (name==NULL) name=strstr(body->body,"signal"); - if (name==NULL) { - ms_warning("Could not extract the dtmf name from the SIP INFO."); - }else{ - char tmp[2]; - name+=strlen("signal"); - if (sscanf(name," = %1s",tmp)==1){ - ms_message("Receiving dtmf %s via SIP INFO.",tmp); - if (sal->callbacks.dtmf_received != NULL) - sal->callbacks.dtmf_received(op, tmp[0]); - } - } - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - } -} - -static void fill_options_answer(osip_message_t *options){ - osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO"); - osip_message_set_accept(options,"application/sdp"); -} - -static void process_refer(Sal *sal, SalOp *op, eXosip_event_t *ev){ - osip_header_t *h=NULL; - osip_message_t *ans=NULL; - ms_message("Receiving REFER request !"); - osip_message_header_get_byname(ev->request,"Refer-To",0,&h); - - if (h){ - osip_from_t *from=NULL; - char *tmp; - osip_from_init(&from); - - if (osip_from_parse(from,h->hvalue)==0){ - if (op ){ - osip_uri_header_t *uh=NULL; - osip_header_t *referred_by=NULL; - osip_uri_header_get_byname(&from->url->url_headers,(char*)"Replaces",&uh); - if (uh!=NULL && uh->gvalue && uh->gvalue[0]!='\0'){ - ms_message("Found replaces in Refer-To"); - if (op->replaces){ - ms_free(op->replaces); - } - op->replaces=ms_strdup(uh->gvalue); - } - osip_message_header_get_byname(ev->request,"Referred-By",0,&referred_by); - if (referred_by && referred_by->hvalue && referred_by->hvalue[0]!='\0'){ - if (op->referred_by) - ms_free(op->referred_by); - op->referred_by=ms_strdup(referred_by->hvalue); - } - } - osip_uri_header_freelist(&from->url->url_headers); - osip_from_to_str(from,&tmp); - sal->callbacks.refer_received(sal,op,tmp); - osip_free(tmp); - osip_from_free(from); - } - eXosip_lock(); - eXosip_call_build_answer(ev->tid,202,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,202,ans); - eXosip_unlock(); - } - else - { - ms_warning("cannot do anything with the refer without destination\n"); - } -} - -static void process_notify(Sal *sal, eXosip_event_t *ev){ - osip_header_t *h=NULL; - char *from=NULL; - SalOp *op=find_op(sal,ev); - osip_message_t *ans=NULL; - - ms_message("Receiving NOTIFY request !"); - osip_from_to_str(ev->request->from,&from); - osip_message_header_get_byname(ev->request,"Event",0,&h); - if(h){ - osip_body_t *body=NULL; - //osip_content_type_t *ct=NULL; - osip_message_get_body(ev->request,0,&body); - //ct=osip_message_get_content_type(ev->request); - if (h->hvalue && strncasecmp(h->hvalue,"refer",strlen("refer"))==0){ - /*special handling of refer events*/ - if (body && body->body){ - osip_message_t *msg; - osip_message_init(&msg); - if (osip_message_parse_sipfrag(msg,body->body,strlen(body->body))==0){ - int code=osip_message_get_status_code(msg); - if (code==100){ - sal->callbacks.notify_refer(op,SalReferTrying); - }else if (code==200){ - sal->callbacks.notify_refer(op,SalReferSuccess); - }else if (code>=400){ - sal->callbacks.notify_refer(op,SalReferFailed); - } - } - osip_message_free(msg); - } - }else{ - /*generic handling*/ - sal->callbacks.notify(op,from,h->hvalue); - } - } - /*answer that we received the notify*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - osip_free(from); -} - -static void call_message_new(Sal *sal, eXosip_event_t *ev){ - osip_message_t *ans=NULL; - if (ev->request){ - if (MSG_IS_INFO(ev->request)){ - osip_content_type_t *ct; - ct=osip_message_get_content_type(ev->request); - if (ct && ct->subtype){ - if (strcmp(ct->subtype,"media_control+xml")==0) - process_media_control_xml(sal,ev); - else if (strcmp(ct->subtype,"dtmf-relay")==0) - process_dtmf_relay(sal,ev); - else { - ms_message("Unhandled SIP INFO."); - /*send an "Not implemented" answer*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,501,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,501,ans); - eXosip_unlock(); - } - }else{ - /*empty SIP INFO, probably to test we are alive. Send an empty answer*/ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - } - }else if(MSG_IS_MESSAGE(ev->request)){ - /* SIP messages could be received into call */ - text_received(sal, ev); - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - eXosip_unlock(); - }else if(MSG_IS_REFER(ev->request)){ - SalOp *op=find_op(sal,ev); - - ms_message("Receiving REFER request !"); - process_refer(sal,op,ev); - }else if(MSG_IS_NOTIFY(ev->request)){ - process_notify(sal,ev); - }else if (MSG_IS_OPTIONS(ev->request)){ - eXosip_lock(); - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans){ - fill_options_answer(ans); - eXosip_call_send_answer(ev->tid,200,ans); - } - eXosip_unlock(); - } - }else ms_warning("call_message_new: No request ?"); -} - -static void inc_update(Sal *sal, eXosip_event_t *ev){ - osip_message_t *msg=NULL; - ms_message("Processing incoming UPDATE"); - eXosip_lock(); - eXosip_message_build_answer(ev->tid,200,&msg); - if (msg!=NULL) - eXosip_message_send_answer(ev->tid,200,msg); - eXosip_unlock(); -} - -static bool_t comes_from_local_if(osip_message_t *msg){ - osip_via_t *via=NULL; - osip_message_get_via(msg,0,&via); - if (via){ - const char *host; - host=osip_via_get_host(via); - if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){ - osip_generic_param_t *param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param==NULL) return TRUE; - if (param->gvalue && - (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){ - return TRUE; - } - } - } - return FALSE; -} - -static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; - -static int utc_offset() { - time_t ref = 24 * 60 * 60L; - struct tm * timeptr; - int gmtime_hours; - - /* get the local reference time for Jan 2, 1900 00:00 UTC */ - timeptr = localtime(&ref); - gmtime_hours = timeptr->tm_hour; - - /* if the local time is the "day before" the UTC, subtract 24 hours - from the hours to get the UTC offset */ - if (timeptr->tm_mday < 2) gmtime_hours -= 24; - - return gmtime_hours; -} - -time_t mktime_utc(struct tm *timeptr) { - return mktime(timeptr) + utc_offset() * 3600; -} - -static void text_received(Sal *sal, eXosip_event_t *ev){ - osip_body_t *body=NULL; - char *from=NULL,*msg=NULL; - osip_content_type_t* content_type; - osip_uri_param_t* external_body_url; - char unquoted_external_body_url [256]; - int external_body_size=0; - SalMessage salmsg; - char message_id[256]={0}; - osip_header_t *date=NULL; - struct tm ret={0}; - char tmp1[80]={0}; - char tmp2[80]={0}; - SalOp *op=sal_op_new(sal); - - osip_message_get_date(ev->request,0,&date); - if(date!=NULL){ - int i,j; - sscanf(date->hvalue,"%3c,%d%s%d%d:%d:%d",tmp1,&ret.tm_mday,tmp2, - &ret.tm_year,&ret.tm_hour,&ret.tm_min,&ret.tm_sec); - ret.tm_year-=1900; - for(i=0;i<7;i++) { - if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; - } - for(j=0;j<12;j++) { - if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; - } - ret.tm_isdst=0; - }else ms_warning("No date header in SIP MESSAGE, we don't know when it was sent."); - - content_type= osip_message_get_content_type(ev->request); - if (!content_type) { - ms_error("Could not get message because no content type"); - return; - } - osip_from_to_str(ev->request->from,&from); - if (content_type->type - && strcmp(content_type->type, "text")==0 - && content_type->subtype - && strcmp(content_type->subtype, "plain")==0 ) { - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("Could not get text message from SIP body"); - osip_free(from); - return; - } - msg=body->body; - }else if (content_type->type - && strcmp(content_type->type, "message")==0 - && content_type->subtype - && strcmp(content_type->subtype, "external-body")==0 ) { - - osip_content_type_param_get_byname(content_type, "URL", &external_body_url); - /*remove both first and last character*/ - strncpy(unquoted_external_body_url - ,&external_body_url->gvalue[1] - ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url))); - unquoted_external_body_url[external_body_size-1]='\0'; - } else { - ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype); - osip_free(from); - return; - } - sal_op_set_custom_header(op,sal_exosip_get_custom_headers(ev->request)); - - snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number); - - salmsg.from=from; - salmsg.text=msg; - salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL; - salmsg.message_id=message_id; - salmsg.time=date!=NULL ? mktime_utc(&ret) : time(NULL); - sal->callbacks.text_received(op,&salmsg); - sal_op_release(op); - osip_free(from); -} - -static void other_request(Sal *sal, eXosip_event_t *ev){ - ms_message("in other_request"); - if (ev->request==NULL) return; - if (strcmp(ev->request->sip_method,"MESSAGE")==0){ - text_received(sal,ev); - eXosip_message_send_answer(ev->tid,200,NULL); - }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){ - osip_message_t *options=NULL; - eXosip_options_build_answer(ev->tid,200,&options); - fill_options_answer(options); - eXosip_options_send_answer(ev->tid,200,options); - }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){ - ms_message("Receiving REFER request !"); - if (comes_from_local_if(ev->request)) { - process_refer(sal,NULL,ev); - }else ms_warning("Ignored REFER not coming from this local loopback interface."); - }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){ - inc_update(sal,ev); - }else { - char *tmp=NULL; - size_t msglen=0; - osip_message_to_str(ev->request,&tmp,&msglen); - if (tmp){ - ms_message("Unsupported request received:\n%s",tmp); - osip_free(tmp); - } - /*answer with a 501 Not implemented*/ - eXosip_message_send_answer(ev->tid,501,NULL); - } -} - -static void masquerade_via(osip_message_t *msg, const char *ip, const char *port){ - osip_via_t *via=NULL; - osip_message_get_via(msg,0,&via); - if (via){ - osip_free(via->port); - via->port=osip_strdup(port); - osip_free(via->host); - via->host=osip_strdup(ip); - } -} - - -static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer, bool_t expire_last_contact) { - osip_contact_t *ctt=NULL; - const char *received; - int rport; - SalTransport transport; - char port[20]; - - if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE; - osip_message_get_contact(request,0,&ctt); - if (ctt == NULL) { - ms_warning("fix_message_contact(): no contact to update"); - return FALSE; - } - if (expire_last_contact){ - osip_contact_t *oldct=NULL,*prevct; - osip_generic_param_t *param=NULL; - osip_contact_clone(ctt,&oldct); - while ((prevct=(osip_contact_t*)osip_list_get(&request->contacts,1))!=NULL){ - osip_contact_free(prevct); - osip_list_remove(&request->contacts,1); - } - osip_list_add(&request->contacts,oldct,1); - osip_contact_param_get_byname(oldct,"expires",¶m); - if (param){ - if (param->gvalue) osip_free(param->gvalue); - param->gvalue=osip_strdup("0"); - }else{ - osip_contact_param_add(oldct,osip_strdup("expires"),osip_strdup("0")); - } - } - if (ctt->url->host!=NULL){ - osip_free(ctt->url->host); - } - ctt->url->host=osip_strdup(received); - if (ctt->url->port!=NULL){ - osip_free(ctt->url->port); - } - snprintf(port,sizeof(port),"%i",rport); - ctt->url->port=osip_strdup(port); - if (op->masquerade_via) masquerade_via(request,received,port); - - if (transport != SalTransportUDP) { - sal_address_set_param((SalAddress *)ctt, "transport", sal_transport_to_string(transport)); - } - return TRUE; -} - -static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){ - osip_contact_t *ctt=NULL; - SalAddress* ori_contact_address=NULL; - const char *received; - int rport; - SalTransport transport; - char* tmp; - osip_message_t *msg=NULL; - Sal* sal=op->base.root; - int i=0; - bool_t found_valid_contact=FALSE; - bool_t from_request=FALSE; - - if (sal->double_reg==FALSE ) return FALSE; - - if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE; - do{ - ctt=NULL; - osip_message_get_contact(last_answer,i,&ctt); - if (!from_request && ctt==NULL) { - osip_message_get_contact(orig_request,0,&ctt); - from_request=TRUE; - } - if (ctt){ - osip_contact_to_str(ctt,&tmp); - ori_contact_address = sal_address_new(tmp); - - /*check if contact is up to date*/ - if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0 - && sal_address_get_port_int(ori_contact_address) == rport - && sal_address_get_transport(ori_contact_address) == transport) { - if (!from_request){ - ms_message("Register response has up to date contact, doing nothing."); - }else { - ms_warning("Register response does not have up to date contact, but last request had." - "Stupid registrar detected, giving up."); - } - found_valid_contact=TRUE; - } - osip_free(tmp); - sal_address_destroy(ori_contact_address); - }else break; - i++; - }while(!found_valid_contact); - if (!found_valid_contact) - ms_message("Contact do not match, resending register."); - else return FALSE; - - eXosip_lock(); - eXosip_register_build_register(op->rid,op->expires,&msg); - if (msg==NULL){ - eXosip_unlock(); - ms_warning("Fail to create a contact updated register."); - return FALSE; - } - if (fix_message_contact(op,msg,last_answer,op->base.root->expire_old_contact)) { - eXosip_register_send_register(op->rid,msg); - eXosip_unlock(); - ms_message("Resending new register with updated contact"); - update_contact_from_response(op,last_answer); - return TRUE; - } else { - ms_warning("Fail to send updated register."); - eXosip_unlock(); - return FALSE; - } - eXosip_unlock(); - return FALSE; -} - -static void registration_success(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_find_register(sal,ev->rid); - osip_header_t *h=NULL; - bool_t registered; - if (op==NULL){ - ms_error("Receiving register response for unknown operation"); - return; - } - osip_message_get_expires(ev->request,0,&h); - if (h!=NULL && atoi(h->hvalue)!=0){ - registered=TRUE; - if (!register_again_with_updated_contact(op,ev->request,ev->response)){ - sal->callbacks.register_success(op,registered); - } - }else { - sal->callbacks.register_success(op,FALSE); - } -} - -static bool_t registration_failure(Sal *sal, eXosip_event_t *ev){ - int status_code=0; - const char *reason=NULL; - SalOp *op=sal_find_register(sal,ev->rid); - SalReason sr=SalReasonUnknown; - SalError se=SalErrorUnknown; - - if (op==NULL){ - ms_error("Receiving register failure for unknown operation"); - return TRUE; - } - if (ev->response){ - status_code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - } - switch(status_code){ - case 401: - case 407: - return process_authentication(sal,ev); - break; - case 423: /*interval too brief*/ - {/*retry with greater interval */ - osip_header_t *h=NULL; - osip_message_t *msg=NULL; - osip_message_header_get_byname(ev->response,"min-expires",0,&h); - if (h && h->hvalue && h->hvalue[0]!='\0'){ - int val=atoi(h->hvalue); - if (val>op->expires) - op->expires=val; - }else op->expires*=2; - eXosip_lock(); - eXosip_register_build_register(op->rid,op->expires,&msg); - eXosip_register_send_register(op->rid,msg); - eXosip_unlock(); - } - break; - case 606: /*Not acceptable, workaround for proxies that don't like private addresses - in vias, such as ekiga.net - On the opposite, freephonie.net bugs when via are masqueraded. - */ - op->masquerade_via=TRUE; - default: - /* if contact is up to date, process the failure, otherwise resend a new register with - updated contact first, just in case the faillure is due to incorrect contact */ - if (ev->response && register_again_with_updated_contact(op,ev->request,ev->response)) - return TRUE; /*we are retrying with an updated contact*/ - if (status_code==403){ - se=SalErrorFailure; - sr=SalReasonForbidden; - }else if (status_code==0){ - se=SalErrorNoResponse; - } - sal->callbacks.register_failure(op,se,sr,reason); - } - return TRUE; -} - -static void other_request_reply(Sal *sal,eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - if (op==NULL){ - ms_warning("other_request_reply(): Receiving response to unknown request."); - return; - } - if (ev->response){ - ms_message("Processing reponse status [%i] for method [%s]",ev->response->status_code,osip_message_get_method(ev->request)); - update_contact_from_response(op,ev->response); - if (ev->request && strcmp(osip_message_get_method(ev->request),"OPTIONS")==0) - sal->callbacks.ping_reply(op); - } - if (ev->request && strcmp(osip_message_get_method(ev->request),"MESSAGE")==0) { - /*out of call message acknolegment*/ - SalTextDeliveryStatus status=SalTextDeliveryFailed; - if (ev->response){ - if (ev->response->status_code<200){ - status=SalTextDeliveryInProgress; - }else if (ev->response->status_code<300 && ev->response->status_code>=200){ - status=SalTextDeliveryDone; - } - } - sal->callbacks.text_delivery_update(op,status); - } -} - -static void process_in_call_reply(Sal *sal, eXosip_event_t *ev){ - SalOp *op=find_op(sal,ev); - if (ev->response){ - if (ev->request && strcmp(osip_message_get_method(ev->request),"NOTIFY")==0){ - if (op->sipfrag_pending){ - send_notify_for_refer(op->did,op->sipfrag_pending); - op->sipfrag_pending=NULL; - } - } - } -} - -static bool_t process_event(Sal *sal, eXosip_event_t *ev){ - ms_message("linphone process event get a message %d\n",ev->type); - switch(ev->type){ - case EXOSIP_CALL_ANSWERED: - ms_message("CALL_ANSWERED\n"); - call_accepted(sal,ev); - authentication_ok(sal,ev); - break; - case EXOSIP_CALL_CLOSED: - case EXOSIP_CALL_CANCELLED: - ms_message("CALL_CLOSED or CANCELLED\n"); - call_terminated(sal,ev); - break; - case EXOSIP_CALL_TIMEOUT: - case EXOSIP_CALL_NOANSWER: - ms_message("CALL_TIMEOUT or NOANSWER\n"); - return call_failure(sal,ev); - break; - case EXOSIP_CALL_REQUESTFAILURE: - case EXOSIP_CALL_GLOBALFAILURE: - case EXOSIP_CALL_SERVERFAILURE: - ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n"); - return call_failure(sal,ev); - break; - case EXOSIP_CALL_RELEASED: - ms_message("CALL_RELEASED\n"); - call_released(sal, ev); - break; - case EXOSIP_CALL_INVITE: - ms_message("CALL_NEW\n"); - inc_new_call(sal,ev); - break; - case EXOSIP_CALL_REINVITE: - handle_reinvite(sal,ev); - break; - case EXOSIP_CALL_ACK: - ms_message("CALL_ACK"); - handle_ack(sal,ev); - break; - case EXOSIP_CALL_REDIRECTED: - ms_message("CALL_REDIRECTED"); - eXosip_default_action(ev); - break; - case EXOSIP_CALL_PROCEEDING: - ms_message("CALL_PROCEEDING"); - call_proceeding(sal,ev); - break; - case EXOSIP_CALL_RINGING: - ms_message("CALL_RINGING"); - call_ringing(sal,ev); - authentication_ok(sal,ev); - break; - case EXOSIP_CALL_MESSAGE_NEW: - ms_message("EXOSIP_CALL_MESSAGE_NEW"); - call_message_new(sal,ev); - break; - case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: - if (ev->response && - (ev->response->status_code==407 || ev->response->status_code==401)){ - return process_authentication(sal,ev); - } - break; - case EXOSIP_CALL_MESSAGE_ANSWERED: - ms_message("EXOSIP_CALL_MESSAGE_ANSWERED "); - process_in_call_reply(sal,ev); - break; - case EXOSIP_IN_SUBSCRIPTION_NEW: - ms_message("CALL_IN_SUBSCRIPTION_NEW "); - sal_exosip_subscription_recv(sal,ev); - break; - case EXOSIP_IN_SUBSCRIPTION_RELEASED: - ms_message("CALL_SUBSCRIPTION_NEW "); - sal_exosip_in_subscription_closed(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_UPDATE: - ms_message("CALL_SUBSCRIPTION_UPDATE"); - break; - case EXOSIP_SUBSCRIPTION_NOTIFY: - ms_message("CALL_SUBSCRIPTION_NOTIFY"); - sal_exosip_notify_recv(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_ANSWERED: - ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i, ev->did=%i\n",ev->sid,ev->did); - sal_exosip_subscription_answered(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_CLOSED: - ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); - sal_exosip_subscription_closed(sal,ev); - break; - case EXOSIP_SUBSCRIPTION_REQUESTFAILURE: /**< announce a request failure */ - if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ - return process_authentication(sal,ev); - } - case EXOSIP_SUBSCRIPTION_SERVERFAILURE: - case EXOSIP_SUBSCRIPTION_GLOBALFAILURE: - sal_exosip_subscription_closed(sal,ev); - break; - case EXOSIP_REGISTRATION_FAILURE: - ms_message("REGISTRATION_FAILURE\n"); - return registration_failure(sal,ev); - break; - case EXOSIP_REGISTRATION_SUCCESS: - authentication_ok(sal,ev); - registration_success(sal,ev); - break; - case EXOSIP_MESSAGE_NEW: - other_request(sal,ev); - break; - case EXOSIP_MESSAGE_PROCEEDING: - case EXOSIP_MESSAGE_ANSWERED: - case EXOSIP_MESSAGE_REDIRECTED: - case EXOSIP_MESSAGE_SERVERFAILURE: - case EXOSIP_MESSAGE_GLOBALFAILURE: - other_request_reply(sal,ev); - break; - case EXOSIP_MESSAGE_REQUESTFAILURE: - case EXOSIP_NOTIFICATION_REQUESTFAILURE: - if (ev->response) { - switch (ev->response->status_code) { - case 407: - case 401: - return process_authentication(sal,ev); - case 412: { - eXosip_automatic_action (); - return 1; - } - } - } - other_request_reply(sal,ev); - break; - default: - ms_message("Unhandled exosip event ! %i",ev->type); - break; - } - return TRUE; -} - -int sal_iterate(Sal *sal){ - eXosip_event_t *ev; - while((ev=eXosip_event_wait(0,0))!=NULL){ - if (process_event(sal,ev)) - eXosip_event_free(ev); - } -#ifdef HAVE_EXOSIP_TRYLOCK - if (eXosip_trylock()==0){ - eXosip_automatic_refresh(); - eXosip_unlock(); - }else{ - ms_warning("eXosip_trylock busy."); - } -#else - eXosip_lock(); - eXosip_automatic_refresh(); - eXosip_unlock(); -#endif - return 0; -} - -static void register_set_contact(osip_message_t *msg, const char *contact){ - osip_uri_param_t *param = NULL; - osip_contact_t *ct=NULL; - char *line=NULL; - /*we get the line parameter choosed by exosip, and add it to our own contact*/ - osip_message_get_contact(msg,0,&ct); - if (ct!=NULL){ - osip_uri_uparam_get_byname(ct->url, "line", ¶m); - if (param && param->gvalue) - line=osip_strdup(param->gvalue); - } - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,contact); - osip_message_get_contact(msg,0,&ct); - osip_uri_uparam_add(ct->url,osip_strdup("line"),line); -} - -void sal_message_add_route(osip_message_t *msg, const char *proxy){ - osip_route_t *route; - - osip_list_special_free(&msg->routes,(void (*)(void*))osip_route_free); - - osip_route_init(&route); - if (osip_route_parse(route,proxy)==0){ - osip_uri_param_t *lr_param = NULL; - osip_uri_uparam_get_byname(route->url, "lr", &lr_param); - if (lr_param == NULL){ - osip_uri_uparam_add(route->url,osip_strdup("lr"),NULL); - } - osip_list_add(&msg->routes,route,0); - return; - } - osip_route_free(route); -} - - -int sal_register(SalOp *h, const char *proxy, const char *from, int expires){ - osip_message_t *msg; - const char *contact=sal_op_get_contact(h); - - sal_op_set_route(h,proxy); - if (h->rid==-1){ - SalAddress *from_parsed=sal_address_new(from); - char domain[256]; - char *uri, *domain_ptr = NULL; - if (from_parsed==NULL) { - ms_warning("sal_register() bad from %s",from); - return -1; - } - /* Get domain using sal_address_as_string_uri_only() and stripping the username part instead of - using sal_address_get_domain() because to have a properly formatted domain with IPv6 proxy addresses. */ - uri = sal_address_as_string_uri_only(from_parsed); - if (uri) domain_ptr = strchr(uri, '@'); - if (domain_ptr) { - snprintf(domain,sizeof(domain),"sip:%s",domain_ptr+1); - } else { - snprintf(domain,sizeof(domain),"sip:%s",sal_address_get_domain(from_parsed)); - } - if (uri) ms_free(uri); - sal_address_destroy(from_parsed); - eXosip_lock(); - h->rid=eXosip_register_build_initial_register(from,domain,NULL,expires,&msg); - if (msg){ - if (contact) register_set_contact(msg,contact); - sal_message_add_route(msg,proxy); - sal_add_register(h->base.root,h); - }else{ - ms_error("Could not build initial register."); - eXosip_unlock(); - return -1; - } - }else{ - eXosip_lock(); - eXosip_register_build_register(h->rid,expires,&msg); - sal_message_add_route(msg,proxy); - } - if (msg){ - eXosip_register_send_register(h->rid,msg); - } - eXosip_unlock(); - h->expires=expires; - return (msg != NULL) ? 0 : -1; -} - -int sal_register_refresh(SalOp *op, int expires){ - osip_message_t *msg=NULL; - const char *contact=sal_op_get_contact(op); - - if (op->rid==-1){ - ms_error("Unexistant registration context, not possible to refresh."); - return -1; - } -#ifdef HAVE_EXOSIP_TRYLOCK - { - int tries=0; - /*iOS hack: in the keep alive handler, we have no more than 10 seconds to refresh registers, otherwise the application is suspended forever. - * In order to prevent this case that can occur when the exosip thread is busy with DNS while network isn't in a good shape, we try to take - * the exosip lock in a non blocking way, and give up if it takes too long*/ - while (eXosip_trylock()!=0){ - ms_usleep(100000); - tries++; - if (tries>30) {/*after 3 seconds, give up*/ - ms_warning("Could not obtain exosip lock in a reasonable time, giving up."); - return -1; - } - } - } -#else - eXosip_lock(); -#endif - eXosip_register_build_register(op->rid,expires,&msg); - if (msg!=NULL){ - if (contact) register_set_contact(msg,contact); - sal_message_add_route(msg,sal_op_get_route(op)); - eXosip_register_send_register(op->rid,msg); - }else ms_error("Could not build REGISTER refresh message."); - eXosip_unlock(); - return (msg != NULL) ? 0 : -1; -} - - -int sal_unregister(SalOp *h){ - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_register_build_register(h->rid,0,&msg); - if (msg) eXosip_register_send_register(h->rid,msg); - else ms_warning("Could not build unREGISTER !"); - eXosip_unlock(); - return 0; -} - -SalAddress * sal_address_new(const char *uri){ - osip_from_t *from; - osip_from_init(&from); - - // Remove front spaces - while (uri[0]==' ') { - uri++; - } - - if (osip_from_parse(from,uri)!=0){ - osip_from_free(from); - return NULL; - } - if (from->displayname!=NULL && from->displayname[0]=='"'){ - char *unquoted=osip_strdup_without_quote(from->displayname); - osip_free(from->displayname); - from->displayname=unquoted; - } - return (SalAddress*)from; -} - -SalAddress * sal_address_clone(const SalAddress *addr){ - osip_from_t *ret=NULL; - osip_from_clone((osip_from_t*)addr,&ret); - return (SalAddress*)ret; -} - -#define null_if_empty(s) (((s)!=NULL && (s)[0]!='\0') ? (s) : NULL ) - -const char *sal_address_get_scheme(const SalAddress *addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->scheme); -} - -const char *sal_address_get_display_name(const SalAddress* addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->displayname); -} - -const char *sal_address_get_username(const SalAddress *addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->username); -} - -const char *sal_address_get_domain(const SalAddress *addr){ - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->host); -} - -void sal_address_set_display_name(SalAddress *addr, const char *display_name){ - osip_from_t *u=(osip_from_t*)addr; - if (u->displayname!=NULL){ - osip_free(u->displayname); - u->displayname=NULL; - } - if (display_name!=NULL && display_name[0]!='\0'){ - u->displayname=osip_strdup(display_name); - } -} - -void sal_address_set_username(SalAddress *addr, const char *username){ - osip_from_t *uri=(osip_from_t*)addr; - if (uri->url->username!=NULL){ - osip_free(uri->url->username); - uri->url->username=NULL; - } - if (username) - uri->url->username=osip_strdup(username); -} - -void sal_address_set_domain(SalAddress *addr, const char *host){ - osip_from_t *uri=(osip_from_t*)addr; - if (uri->url->host!=NULL){ - osip_free(uri->url->host); - uri->url->host=NULL; - } - if (host) - uri->url->host=osip_strdup(host); -} - -void sal_address_set_port(SalAddress *addr, const char *port){ - osip_from_t *uri=(osip_from_t*)addr; - if (uri->url->port!=NULL){ - osip_free(uri->url->port); - uri->url->port=NULL; - } - if (port) - uri->url->port=osip_strdup(port); -} - -void sal_address_set_port_int(SalAddress *uri, int port){ - char tmp[12]; - if (port==5060){ - /*this is the default, special case to leave the port field blank*/ - sal_address_set_port(uri,NULL); - return; - } - snprintf(tmp,sizeof(tmp),"%i",port); - sal_address_set_port(uri,tmp); -} - -void sal_address_clean(SalAddress *addr){ - osip_generic_param_freelist(& ((osip_from_t*)addr)->gen_params); - osip_uri_param_freelist(& ((osip_from_t*)addr)->url->url_params); -} - -char *sal_address_as_string(const SalAddress *u){ - char *tmp,*ret; - osip_from_t *from=(osip_from_t *)u; - char *old_displayname=NULL; - /* hack to force use of quotes around the displayname*/ - if (from->displayname!=NULL - && from->displayname[0]!='"'){ - old_displayname=from->displayname; - from->displayname=osip_enquote(from->displayname); - } - osip_from_to_str(from,&tmp); - if (old_displayname!=NULL){ - ms_free(from->displayname); - from->displayname=old_displayname; - } - ret=ms_strdup(tmp); - osip_free(tmp); - return ret; -} - -char *sal_address_as_string_uri_only(const SalAddress *u){ - char *tmp=NULL,*ret; - osip_uri_to_str(((osip_from_t*)u)->url,&tmp); - ret=ms_strdup(tmp); - osip_free(tmp); - return ret; -} -void sal_address_set_param(SalAddress *u,const char* name,const char* value) { - osip_uri_param_t *param=NULL; - osip_uri_uparam_get_byname(((osip_from_t*)u)->url,(char*)name,¶m); - if (param == NULL){ - osip_uri_uparam_add (((osip_from_t*)u)->url,ms_strdup(name),value ? ms_strdup(value) : NULL); - } else { - osip_free(param->gvalue); - param->gvalue=value ? osip_strdup(value) : NULL; - } - -} - -void sal_address_destroy(SalAddress *u){ - osip_from_free((osip_from_t*)u); -} - -void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled) { - ctx->tcp_tls_keepalive = enabled; -} - -void sal_set_keepalive_period(Sal *ctx,unsigned int value) { - switch (ctx->transport) { - case SalTransportUDP: - ctx->keepalive_period = value; - break; - case SalTransportTCP: - case SalTransportTLS: - if (ctx->tcp_tls_keepalive) ctx->keepalive_period = value; - else ctx->keepalive_period = -1; - break; - default: - break; - } - eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &ctx->keepalive_period); -} -unsigned int sal_get_keepalive_period(Sal *ctx) { - return ctx->keepalive_period; -} - -const char * sal_address_get_port(const SalAddress *addr) { - const osip_from_t *u=(const osip_from_t*)addr; - return null_if_empty(u->url->port); -} - -int sal_address_get_port_int(const SalAddress *uri) { - const char* port = sal_address_get_port(uri); - if (port != NULL) { - return atoi(port); - } else { - return 5060; - } -} -SalTransport sal_address_get_transport(const SalAddress* addr) { - const osip_from_t *u=(const osip_from_t*)addr; - osip_uri_param_t *transport_param=NULL; - osip_uri_uparam_get_byname(u->url,"transport",&transport_param); - if (transport_param == NULL){ - return SalTransportUDP; - } else { - return sal_transport_parse(transport_param->gvalue); - } -} -void sal_address_set_transport(SalAddress* addr,SalTransport transport) { - sal_address_set_param(addr, "transport", sal_transport_to_string(transport)); -} - -/* sends a reinvite. Local media description may have changed by application since call establishment*/ -int sal_call_update(SalOp *h, const char *subject){ - int err=0; - osip_message_t *reinvite=NULL; - - eXosip_lock(); - if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != 0 || reinvite==NULL){ - eXosip_unlock(); - return -1; - } - eXosip_unlock(); - osip_message_set_subject(reinvite,subject); - osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); - if (h->base.contact){ - _osip_list_set_empty(&reinvite->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(reinvite,h->base.contact); - } - if (h->base.root->session_expires!=0){ - osip_message_set_header(reinvite, "Session-expires", "200"); - osip_message_set_supported(reinvite, "timer"); - } - if (h->base.local_media){ - h->sdp_offering=TRUE; - set_sdp_from_desc(reinvite,h->base.local_media); - }else h->sdp_offering=FALSE; - eXosip_lock(); - err = eXosip_call_send_request(h->did, reinvite); - eXosip_unlock(); - return err; -} - -void sal_reuse_authorization(Sal *ctx, bool_t value) { - ctx->reuse_authorization=value; -} - -void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch){ - MSList *elem=(MSList*)ch; - for (;elem!=NULL;elem=elem->next){ - SalCustomHeader *it=(SalCustomHeader*)elem; - osip_message_set_header(msg,it->header_name,it->header_value); - } -} - -SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg){ - int i=0; - osip_header_t *header; - SalCustomHeader *ret=NULL; - - while((header=osip_list_get(&msg->headers,i))!=NULL){ - ret=sal_custom_header_append(ret,header->hname,header->hvalue); - i++; - } - return ret; -} - diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h deleted file mode 100644 index e00dd64d9..000000000 --- a/coreapi/sal_eXosip2.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -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. -*/ - -#ifndef sal_exosip2_h -#define sal_exosip2_h - -#include "sal.h" -#include - - - -sdp_message_t *media_description_to_sdp(const SalMediaDescription *sal); -int sdp_to_media_description(sdp_message_t *sdp, SalMediaDescription *desc); - -struct Sal{ - SalCallbacks callbacks; - SalTransport transport; - MSList *calls; /*MSList of SalOp */ - MSList *registers;/*MSList of SalOp */ - MSList *out_subscribes;/*MSList of SalOp */ - MSList *in_subscribes;/*MSList of SalOp */ - MSList *pending_auths;/*MSList of SalOp */ - MSList *other_transactions; /*MSList of SalOp */ - int running; - int session_expires; - int keepalive_period; - void *up; /*user pointer*/ - char* rootCa; /* File _or_ folder containing root CA */ - int dscp; - bool_t one_matching_codec; - bool_t double_reg; - bool_t use_rports; - bool_t use_101; - bool_t reuse_authorization; - bool_t verify_server_certs; - bool_t verify_server_cn; - bool_t expire_old_contact; - bool_t add_dates; - bool_t tcp_tls_keepalive; -}; - -struct SalOp{ - SalOpBase base; - int cid; - int did; - int tid; - int rid; - int sid; - int nid; - int expires; - SalMediaDescription *result; - sdp_message_t *sdp_answer; - eXosip_event_t *pending_auth; - osip_call_id_t *call_id; /*used for out of calls transaction in order - to retrieve the operation when receiving a response*/ - char *replaces; - char *referred_by; - const SalAuthInfo *auth_info; - const char *sipfrag_pending; - bool_t supports_session_timers; - bool_t sdp_offering; - bool_t reinvite; - bool_t masquerade_via; - bool_t auto_answer_asked; - bool_t terminated; -}; - -void sal_remove_out_subscribe(Sal *sal, SalOp *op); -void sal_remove_in_subscribe(Sal *sal, SalOp *op); -void sal_add_other(Sal *sal, SalOp *op, osip_message_t *request); - -void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev); -void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev); -void sal_exosip_notify_recv(Sal *sal,eXosip_event_t *ev); -void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev); - -void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev); -SalOp * sal_find_out_subscribe(Sal *sal, int sid); -SalOp * sal_find_in_subscribe(Sal *sal, int nid); -void sal_exosip_fix_route(SalOp *op); -void sal_exosip_add_custom_headers(osip_message_t *msg, SalCustomHeader *ch); -SalCustomHeader * sal_exosip_get_custom_headers(osip_message_t *msg); - -void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)); - -void sal_message_add_route(osip_message_t *msg, const char *proxy); - -#endif diff --git a/coreapi/sal_eXosip2_presence.c b/coreapi/sal_eXosip2_presence.c deleted file mode 100644 index b9f7b5763..000000000 --- a/coreapi/sal_eXosip2_presence.c +++ /dev/null @@ -1,809 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -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 "sal_eXosip2.h" - -typedef enum { - PIDF = 0, - RFCxxxx = 1, - MSOLDPRES = 2 -} presence_type_t; - -/* - * REVISIT: this static variable forces every dialog to use the same presence description type depending - * on what is received on a single dialog... - */ -static presence_type_t presence_style = PIDF; - -SalOp * sal_find_out_subscribe(Sal *sal, int sid){ - const MSList *elem; - SalOp *op; - for(elem=sal->out_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->sid==sid) return op; - } - ms_message("No op for sid %i",sid); - return NULL; -} - -static void sal_add_out_subscribe(Sal *sal, SalOp *op){ - sal->out_subscribes=ms_list_append(sal->out_subscribes,op); -} - -void sal_remove_out_subscribe(Sal *sal, SalOp *op){ - sal->out_subscribes=ms_list_remove(sal->out_subscribes,op); -} - -SalOp * sal_find_in_subscribe(Sal *sal, int nid){ - const MSList *elem; - SalOp *op; - for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->nid==nid) return op; - } - return NULL; -} - -static SalOp * sal_find_in_subscribe_by_call_id(Sal *sal, osip_call_id_t *call_id){ - const MSList *elem; - SalOp *op; - for(elem=sal->in_subscribes;elem!=NULL;elem=elem->next){ - op=(SalOp*)elem->data; - if (op->call_id && osip_call_id_match(op->call_id,call_id)==0) - return op; - } - return NULL; -} - -static void sal_add_in_subscribe(Sal *sal, SalOp *op, osip_message_t *subs){ - osip_call_id_clone(subs->call_id,&op->call_id); - sal->in_subscribes=ms_list_append(sal->in_subscribes,op); -} - -void sal_remove_in_subscribe(Sal *sal, SalOp *op){ - sal->in_subscribes=ms_list_remove(sal->in_subscribes,op); -} - -static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; - -static void msg_add_current_date(osip_message_t *msg){ - char tmp[64]={0}; - time_t curtime=time(NULL); - struct tm *ret; -#ifndef WIN32 - struct tm gmt; - ret=gmtime_r(&curtime,&gmt); -#else - ret=gmtime(&curtime); -#endif - /*cannot use strftime because it is locale dependant*/ - snprintf(tmp,sizeof(tmp)-1,"%s, %i %s %i %02i:%02i:%02i GMT", - days[ret->tm_wday],ret->tm_mday,months[ret->tm_mon],1900+ret->tm_year,ret->tm_hour,ret->tm_min,ret->tm_sec); - osip_message_replace_header(msg,"Date",tmp); -} - - -int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg){ - osip_message_t *sip=NULL; - - if(op->cid == -1) - { - /* we are not currently in communication with the destination */ - if (from) - sal_op_set_from(op,from); - if (to) - sal_op_set_to(op,to); - - sal_exosip_fix_route(op); - eXosip_lock(); - eXosip_message_build_request(&sip,"MESSAGE",sal_op_get_to(op), - sal_op_get_from(op),sal_op_get_route(op)); - if (sip!=NULL){ - sal_exosip_add_custom_headers(sip,op->base.custom_headers); - msg_add_current_date(sip); - osip_message_set_content_type(sip,content_type); - if (msg) osip_message_set_body(sip,msg,strlen(msg)); - sal_add_other(op->base.root,op,sip); - eXosip_message_send_request(sip); - }else{ - ms_error("Could not build MESSAGE request !"); - } - eXosip_unlock(); - } - else - { - /* we are currently in communication with the destination */ - eXosip_lock(); - //First we generate an INFO message to get the current call_id and a good cseq - eXosip_call_build_request(op->did,"MESSAGE",&sip); - if(sip == NULL) - { - ms_warning("could not get a build info to send MESSAGE, maybe no previous call established ?"); - eXosip_unlock(); - return -1; - } - sal_exosip_add_custom_headers(sip,op->base.custom_headers); - msg_add_current_date(sip); - osip_message_set_content_type(sip,content_type); - if (msg) osip_message_set_body(sip,msg,strlen(msg)); - eXosip_call_send_request(op->did,sip); - eXosip_unlock(); - } - return 0; -} - -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); -} -/*presence Subscribe/notify*/ -int sal_subscribe_presence(SalOp *op, const char *from, const char *to){ - osip_message_t *msg=NULL; - if (from) - sal_op_set_from(op,from); - if (to) - sal_op_set_to(op,to); - sal_exosip_fix_route(op); - eXosip_lock(); - eXosip_subscribe_build_initial_request(&msg,sal_op_get_to(op),sal_op_get_from(op), - sal_op_get_route(op),"presence",600); - if (msg==NULL){ - ms_error("Could not build subscribe request to %s",to); - eXosip_unlock(); - return -1; - } - if (op->base.contact){ - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,op->base.contact); - } - op->sid=eXosip_subscribe_send_initial_request(msg); - eXosip_unlock(); - if (op->sid==-1){ - osip_message_free(msg); - return -1; - } - sal_add_out_subscribe(op->base.root,op); - return 0; -} - -int sal_unsubscribe(SalOp *op){ - osip_message_t *msg=NULL; - if (op->did==-1){ - ms_error("cannot unsubscribe, no dialog !"); - return -1; - } - eXosip_lock(); - eXosip_subscribe_build_refresh_request(op->did,&msg); - if (msg){ - osip_message_set_expires(msg,"0"); - eXosip_subscribe_send_refresh_request(op->did,msg); - }else ms_error("Could not build subscribe refresh request ! op->sid=%i, op->did=%i", - op->sid,op->did); - eXosip_unlock(); - return 0; -} - -int sal_subscribe_accept(SalOp *op){ - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_insubscription_build_answer(op->tid,202,&msg); - if (msg==NULL){ - ms_error("Fail to build answer to subscribe."); - eXosip_unlock(); - return -1; - } - if (op->base.contact){ - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,op->base.contact); - } - eXosip_insubscription_send_answer(op->tid,202,msg); - eXosip_unlock(); - return 0; -} - -int sal_subscribe_decline(SalOp *op){ - eXosip_lock(); - eXosip_insubscription_send_answer(op->tid,401,NULL); - eXosip_unlock(); - return 0; -} - -static void mk_presence_body (const SalPresenceStatus online_status, const char *contact_info, - char *buf, size_t buflen, presence_type_t ptype) { - switch (ptype) { - case RFCxxxx: { - /* definition from http://msdn.microsoft.com/en-us/library/cc246202%28PROT.10%29.aspx */ - int atom_id = 1000; - - if (online_status==SalPresenceOnline) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceBusy || - online_status == SalPresenceDonotdisturb) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceBerightback) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceAway || - online_status == SalPresenceMoved) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOnthephone) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOuttolunch) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - } - break; - } - case MSOLDPRES: { - /* Couldn't find schema http://schemas.microsoft.com/2002/09/sip/presence - * so messages format has been taken from Communigate that can send notify - * requests with this schema - */ - int atom_id = 1000; - - if (online_status==SalPresenceOnline) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceBusy || - online_status == SalPresenceDonotdisturb) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceBerightback) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status == SalPresenceAway || - online_status == SalPresenceMoved) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOnthephone) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else if (online_status==SalPresenceOuttolunch) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - - } - else - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"\n" -"\n" -"
\n" -"\n" -"\n" -"
\n" -"
\n" -"
", contact_info, atom_id, contact_info); - } - break; - } - default: { /* use pidf+xml as default format, rfc4479, rfc4480, rfc3863 */ - - if (online_status==SalPresenceOnline) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status == SalPresenceBusy || - online_status == SalPresenceDonotdisturb) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status==SalPresenceBerightback) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status == SalPresenceAway || - online_status == SalPresenceMoved) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status==SalPresenceOnthephone) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"\n" -"", -contact_info, contact_info); - } - else if (online_status==SalPresenceOuttolunch) - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"open\n" -"%s\n" -"\n" -"\n" -"\n" -"Out to lunch \n" -"\n" -"", -contact_info, contact_info); - } - else - { - snprintf(buf, buflen, "\n" -"\n" -"\n" -"closed\n" -"%s\n" -"\n" -"\n", contact_info, contact_info); - } - break; - } - } // switch - -} - -static void add_presence_body(osip_message_t *notify, SalPresenceStatus online_status) -{ - char buf[1000]; - char *contact_info; - - osip_from_t *from=NULL; - from=osip_message_get_from(notify); - osip_uri_to_str(from->url,&contact_info); - - mk_presence_body (online_status, contact_info, buf, sizeof (buf), presence_style); - - osip_message_set_body(notify, buf, strlen(buf)); - osip_message_set_content_type(notify, - presence_style ? "application/xpidf+xml" : "application/pidf+xml"); - - osip_free(contact_info); -} - - -int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message){ - osip_message_t *msg=NULL; - eXosip_ss_t ss=EXOSIP_SUBCRSTATE_ACTIVE; - if (op->nid==-1){ - ms_warning("Cannot notify, subscription was closed."); - return -1; - } - - eXosip_lock(); - eXosip_insubscription_build_notify(op->did,ss,DEACTIVATED,&msg); - if (msg!=NULL){ - const char *identity=sal_op_get_contact(op); - if (identity==NULL) identity=sal_op_get_to(op); - _osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free); - osip_message_set_contact(msg,identity); - add_presence_body(msg,status); - eXosip_insubscription_send_request(op->did,msg); - }else ms_error("could not create notify for incoming subscription."); - eXosip_unlock(); - return 0; -} - -int sal_notify_close(SalOp *op){ - osip_message_t *msg=NULL; - eXosip_lock(); - eXosip_insubscription_build_notify(op->did,EXOSIP_SUBCRSTATE_TERMINATED,DEACTIVATED,&msg); - if (msg!=NULL){ - const char *identity=sal_op_get_contact(op); - if (identity==NULL) identity=sal_op_get_to(op); - osip_message_set_contact(msg,identity); - add_presence_body(msg,SalPresenceOffline); - eXosip_insubscription_send_request(op->did,msg); - }else ms_error("sal_notify_close(): could not create notify for incoming subscription" - " did=%i, nid=%i",op->did,op->nid); - eXosip_unlock(); - return 0; -} - -int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus presence_mode){ - osip_message_t *pub; - int i; - char buf[1024]; - const char *route=sal_op_get_route(op); - - mk_presence_body (presence_mode, from, buf, sizeof (buf), presence_style); - - i = eXosip_build_publish(&pub,to, from, NULL, "presence", "600", - presence_style ? "application/xpidf+xml" : "application/pidf+xml", buf); - if (i<0){ - ms_warning("Failed to build publish request."); - return -1; - } - if (route) - sal_message_add_route(pub,route); - - eXosip_lock(); - i = eXosip_publish(pub, to); /* should update the sip-if-match parameter - from sip-etag from last 200ok of PUBLISH */ - eXosip_unlock(); - if (i<0){ - ms_message("Failed to send publish request."); - return -1; - } - sal_add_other(sal_op_get_sal(op),op,pub); - return 0; -} - -static void _sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_op_new(sal); - char *tmp; - op->did=ev->did; - op->tid=ev->tid; - op->nid=ev->nid; - osip_from_to_str(ev->request->from,&tmp); - sal_op_set_from(op,tmp); - ms_free(tmp); - osip_from_to_str(ev->request->to,&tmp); - sal_op_set_to(op,tmp); - ms_free(tmp); - sal_add_in_subscribe(sal,op,ev->request); - sal->callbacks.subscribe_received(op,sal_op_get_from(op)); -} - -void sal_exosip_subscription_recv(Sal *sal, eXosip_event_t *ev){ - /*workaround a bug in eXosip: incoming SUBSCRIBES within dialog with expires: 0 are - recognized as new incoming subscribes*/ - SalOp *op=sal_find_in_subscribe_by_call_id(sal,ev->request->call_id); - if (op){ - osip_header_t *h; - osip_message_header_get_byname(ev->request,"expires",0,&h); - if (h && h->hvalue && atoi(h->hvalue)==0){ - ms_warning("This susbscribe is not a new one but terminates an old one."); - ev->did=op->did; - ev->nid=op->nid; - sal_exosip_subscription_closed(sal,ev); - }else { - osip_message_t *msg=NULL; - ms_warning("Probably a refresh subscribe"); - eXosip_lock(); - eXosip_insubscription_build_answer(ev->tid,202,&msg); - eXosip_insubscription_send_answer(ev->tid,202,msg); - eXosip_unlock(); - } - }else _sal_exosip_subscription_recv(sal,ev); -} - -void sal_exosip_notify_recv(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_find_out_subscribe(sal,ev->sid); - char *tmp; - osip_from_t *from=NULL; - osip_body_t *body=NULL; - SalPresenceStatus estatus=SalPresenceOffline; - - ms_message("Receiving notify with sid=%i,nid=%i",ev->sid,ev->nid); - - if (op==NULL){ - ms_error("No operation related to this notify !"); - return; - } - if (ev->request==NULL) return; - - from=ev->request->from; - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("No body in NOTIFY"); - return; - } - osip_from_to_str(from,&tmp); - if (strstr(body->body,"pending")!=NULL){ - estatus=SalPresenceOffline; - }else if (strstr(body->body,"busy")!=NULL){ - estatus=SalPresenceBusy; - }else if (strstr(body->body,"berightback")!=NULL - || strstr(body->body,"in-transit")!=NULL ){ - estatus=SalPresenceBerightback; - }else if (strstr(body->body,"away")!=NULL - || strstr(body->body,"idle")){ - estatus=SalPresenceAway; - }else if (strstr(body->body,"onthephone")!=NULL - || strstr(body->body,"on-the-phone")!=NULL){ - estatus=SalPresenceOnthephone; - }else if (strstr(body->body,"outtolunch")!=NULL - || strstr(body->body,"meal")!=NULL){ - estatus=SalPresenceOuttolunch; - }else if (strstr(body->body,"closed")!=NULL){ - estatus=SalPresenceOffline; - }else if ((strstr(body->body,"online")!=NULL) || (strstr(body->body,"open")!=NULL)) { - estatus=SalPresenceOnline; - }else{ - estatus=SalPresenceOffline; - } - ms_message("We are notified that %s has online status %i",tmp,estatus); - if (ev->ss_status==EXOSIP_SUBCRSTATE_TERMINATED) { - sal_remove_out_subscribe(sal,op); - op->sid=-1; - op->did=-1; - ms_message("And outgoing subscription terminated by remote."); - } - sal->callbacks.notify_presence(op,op->sid!=-1 ? SalSubscribeActive : SalSubscribeTerminated, estatus,NULL); - - /* try to detect presence message style used by server, - * and switch our presence messages to servers style */ - if (strstr (body->body, "//IETF//DTD RFCxxxx XPIDF 1.0//EN") != NULL) { - presence_style = RFCxxxx; - } else if (strstr(body->body,"http://schemas.microsoft.com/2002/09/sip/presence")!=NULL) { - presence_style = MSOLDPRES; - } - - osip_free(tmp); -} - -void sal_exosip_subscription_answered(Sal *sal,eXosip_event_t *ev){ - SalOp *op=sal_find_out_subscribe(sal,ev->sid); - if (op==NULL){ - ms_error("Subscription answered but no associated op !"); - return; - } - op->did=ev->did; -} - -void sal_exosip_in_subscription_closed(Sal *sal, eXosip_event_t *ev){ - SalOp *op=sal_find_in_subscribe(sal,ev->nid); - char *tmp; - if (op==NULL){ - ms_error("Incoming subscription closed but no associated op !"); - return; - } - - - sal_remove_in_subscribe(sal,op); - op->nid=-1; - op->did=-1; - if (ev->request){ - osip_from_to_str(ev->request->from,&tmp); - sal->callbacks.subscribe_closed(op,tmp); - osip_free(tmp); - } -} - -void sal_exosip_subscription_closed(Sal *sal,eXosip_event_t *ev){ - SalOp *op=sal_find_out_subscribe(sal,ev->sid); - if (op==NULL){ - ms_error("Subscription closed but no associated op !"); - return; - } - sal_remove_out_subscribe(sal,op); - op->sid=-1; - op->did=-1; - sal->callbacks.notify_presence(op,SalSubscribeTerminated, SalPresenceOffline,NULL); -} - - diff --git a/coreapi/sal_eXosip2_sdp.c b/coreapi/sal_eXosip2_sdp.c deleted file mode 100644 index 54865aab6..000000000 --- a/coreapi/sal_eXosip2_sdp.c +++ /dev/null @@ -1,618 +0,0 @@ -/* -linphone -Copyright (C) 2010 Simon MORLAT (simon.morlat@free.fr) - -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 "ortp/port.h" -#include "ortp/b64.h" -#include "ortp/ortp_srtp.h" -#include "sal.h" -#include - -#define keywordcmp(key,b) strcmp(key,b) - -#ifdef FOR_LATER - -static char *make_relay_session_id(const char *username, const char *relay){ - /*ideally this should be a hash of the parameters with a random part*/ - char tmp[128]; - int s1=(int)random(); - int s2=(int)random(); - long long int res=((long long int)s1)<<32 | (long long int) s2; - void *src=&res; - b64_encode(src, sizeof(long long int), tmp, sizeof(tmp)); - return osip_strdup(tmp); -} - - -static void add_relay_info(sdp_message_t *sdp, int mline, const char *relay, const char *relay_session_id){ - - if (relay) sdp_message_a_attribute_add(sdp, mline, - osip_strdup ("relay-addr"),osip_strdup(relay)); - if (relay_session_id) sdp_message_a_attribute_add(sdp, mline, - osip_strdup ("relay-session-id"), osip_strdup(relay_session_id)); -} - -#endif - -static char * int_2char(int a){ - char *p=osip_malloc(16); - snprintf(p,16,"%i",a); - return p; -} - -/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/ -static const char *sdp_message_a_attr_value_get_with_pt(sdp_message_t *sdp,int pos,int pt,const char *field) -{ - int i,tmppt=0,scanned=0; - char *tmp; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ - if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ - int nb = sscanf(attr->a_att_value,"%i %n",&tmppt,&scanned); - /* the return value may depend on how %n is interpreted by the libc: see manpage*/ - if (nb == 1 || nb==2 ){ - if (pt==tmppt){ - tmp=attr->a_att_value+scanned; - if (strlen(tmp)>0) - return tmp; - } - }else ms_warning("sdp has a strange a= line (%s) nb=%i",attr->a_att_value,nb); - } - } - return NULL; -} - -#ifdef FOR_LATER -/* return the value of attr "field" */ -static const char *sdp_message_a_attr_value_get(sdp_message_t *sdp,int pos,const char *field) -{ - int i; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,pos,i))!=NULL;i++){ - if (keywordcmp(field,attr->a_att_field)==0 && attr->a_att_value!=NULL){ - return attr->a_att_value; - } - } - return NULL; -} -#endif - -static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){ - int i,ret; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){ - if (keywordcmp("ptime",attr->a_att_field)==0){ - int nb = sscanf(attr->a_att_value,"%i",&ret); - /* the return value may depend on how %n is interpreted by the libc: see manpage*/ - if (nb == 1){ - return ret; - }else ms_warning("sdp has a strange a=ptime line (%s) ",attr->a_att_value); - } - } - return 0; -} - -static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){ - int i; - sdp_attribute_t *attr; - for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){ - if (keywordcmp("sendrecv",attr->a_att_field)==0){ - return SalStreamSendRecv; - }else if (keywordcmp("sendonly",attr->a_att_field)==0){ - return SalStreamSendOnly; - }else if (keywordcmp("recvonly",attr->a_att_field)==0){ - return SalStreamRecvOnly; - }else if (keywordcmp("inactive",attr->a_att_field)==0){ - return SalStreamInactive; - } - } - return SalStreamSendRecv; -} - -static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc) -{ - sdp_message_t *local; - int inet6; - char sessid[16]; - char sessver[16]; - const char *rtp_addr = desc->addr; - - snprintf(sessid,16,"%i",desc->session_id); - snprintf(sessver,16,"%i",desc->session_ver); - sdp_message_init (&local); - if (strchr(desc->addr,':')!=NULL){ - inet6=1; - }else inet6=0; - sdp_message_v_version_set (local, osip_strdup ("0")); - sdp_message_o_origin_set (local, osip_strdup (desc->username), - osip_strdup (sessid), osip_strdup (sessver), - osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"), - osip_strdup (desc->addr)); - sdp_message_s_name_set (local, osip_strdup ("Talk")); - /* Do not set the c= line to 0.0.0.0 if there is an ICE session. */ - if((desc->ice_ufrag[0] != '\0') || !sal_media_description_has_dir (desc,SalStreamSendOnly)) - { - sdp_message_c_connection_add (local, -1, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (rtp_addr), NULL, NULL); - } - else - { - sdp_message_c_connection_add (local, -1, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - inet6 ? osip_strdup ("::0") : osip_strdup ("0.0.0.0"), NULL, NULL); - } - sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0")); - if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"), - int_2char(desc->bandwidth)); - if (desc->ice_completed == TRUE) sdp_message_a_attribute_add(local, -1, osip_strdup("nortpproxy"), osip_strdup("yes")); - if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd)); - if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(local, -1, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag)); - - return local; -} - - -static bool_t is_known_rtpmap(const PayloadType *pt){ - switch(payload_type_get_number(pt)){ - case 0: - case 8: - case 3: - case 34: - return TRUE; - } - return FALSE; -} - -static void add_payload(sdp_message_t *msg, int line, const PayloadType *pt, bool_t strip_well_known_rtpmaps) -{ - char attr[256]; - sdp_message_m_payload_add (msg,line, int_2char (payload_type_get_number(pt))); - - if (!strip_well_known_rtpmaps || !is_known_rtpmap(pt)){ - if (pt->channels>1) - snprintf (attr,sizeof(attr),"%i %s/%i/%i", payload_type_get_number(pt), - pt->mime_type, pt->clock_rate,pt->channels); - else - snprintf (attr,sizeof(attr),"%i %s/%i", payload_type_get_number(pt), - pt->mime_type, pt->clock_rate); - sdp_message_a_attribute_add (msg, line, - osip_strdup ("rtpmap"), osip_strdup(attr)); - } - - if (pt->recv_fmtp != NULL) - { - snprintf (attr,sizeof(attr),"%i %s", payload_type_get_number(pt),pt->recv_fmtp); - sdp_message_a_attribute_add (msg, line, osip_strdup ("fmtp"), - osip_strdup(attr)); - } -} - -static void add_ice_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) -{ - char buffer[1024]; - const SalIceCandidate *candidate; - int nb; - int i; - - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; i++) { - candidate = &desc->ice_candidates[i]; - if ((candidate->addr[0] == '\0') || (candidate->port == 0)) break; - nb = snprintf(buffer, sizeof(buffer), "%s %u UDP %u %s %d typ %s", - candidate->foundation, candidate->componentID, candidate->priority, candidate->addr, candidate->port, candidate->type); - if (nb < 0) { - ms_error("Cannot add ICE candidate attribute!"); - return; - } - if (candidate->raddr[0] != '\0') { - nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport); - if (nb < 0) { - ms_error("Cannot add ICE candidate attribute!"); - return; - } - } - sdp_message_a_attribute_add(msg, lineno, osip_strdup("candidate"), osip_strdup(buffer)); - } -} - -static void add_ice_remote_candidates(sdp_message_t *msg, int lineno, const SalStreamDescription *desc) -{ - char buffer[1024]; - char *ptr = buffer; - const SalIceRemoteCandidate *candidate; - int offset = 0; - int i; - - buffer[0] = '\0'; - for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) { - candidate = &desc->ice_remote_candidates[i]; - if ((candidate->addr[0] != '\0') && (candidate->port != 0)) { - offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port); - if (offset < 0) { - ms_error("Cannot add ICE remote-candidates attribute!"); - return; - } - ptr += offset; - } - } - if (buffer[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("remote-candidates"), osip_strdup(buffer)); -} - -static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription *desc){ - const char *mt=NULL; - const MSList *elem; - const char *rtp_addr; - const char *rtcp_addr; - const char *dir="sendrecv"; - int rtp_port; - int rtcp_port; - bool_t strip_well_known_rtpmaps; - bool_t different_rtp_and_rtcp_addr; - - switch (desc->type) { - case SalAudio: - mt="audio"; - break; - case SalVideo: - mt="video"; - break; - case SalOther: - mt=desc->typeother; - break; - } - rtp_addr=desc->rtp_addr; - rtcp_addr=desc->rtcp_addr; - rtp_port=desc->rtp_port; - rtcp_port=desc->rtcp_port; - - if (desc->proto == SalProtoRtpSavp) { - int i; - - sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (rtp_port), NULL, - osip_strdup ("RTP/SAVP")); - - /* add crypto lines */ - for(i=0; icrypto[i].algo) { - case AES_128_SHA1_80: - snprintf(buffer, 1024, "%d %s inline:%s", - desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_80", desc->crypto[i].master_key); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"), - osip_strdup(buffer)); - break; - case AES_128_SHA1_32: - snprintf(buffer, 1024, "%d %s inline:%s", - desc->crypto[i].tag, "AES_CM_128_HMAC_SHA1_32", desc->crypto[i].master_key); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("crypto"), - osip_strdup(buffer)); - break; - case AES_128_NO_AUTH: - ms_warning("Unsupported crypto suite: AES_128_NO_AUTH"); - break; - case NO_CIPHER_SHA1_80: - ms_warning("Unsupported crypto suite: NO_CIPHER_SHA1_80"); - break; - default: - i = SAL_CRYPTO_ALGO_MAX; - } - } - - } else { - sdp_message_m_media_add (msg, osip_strdup (mt), - int_2char (rtp_port), NULL, - osip_strdup ("RTP/AVP")); - - } - - /*only add a c= line within the stream description if address are differents*/ - if (rtp_addr[0]!='\0' && strcmp(rtp_addr,sdp_message_c_addr_get(msg, -1, 0))!=0){ - bool_t inet6; - if (strchr(rtp_addr,':')!=NULL){ - inet6=TRUE; - }else inet6=FALSE; - sdp_message_c_connection_add (msg, lineno, - osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"), - osip_strdup (rtp_addr), NULL, NULL); - } - - if (desc->bandwidth>0) sdp_message_b_bandwidth_add (msg, lineno, osip_strdup ("AS"), - int_2char(desc->bandwidth)); - if (desc->ptime>0) sdp_message_a_attribute_add(msg,lineno,osip_strdup("ptime"), - int_2char(desc->ptime)); - strip_well_known_rtpmaps=ms_list_size(desc->payloads)>5; - if (desc->payloads){ - for(elem=desc->payloads;elem!=NULL;elem=elem->next){ - add_payload(msg, lineno, (PayloadType*)elem->data,strip_well_known_rtpmaps); - } - }else{ - /* to comply with SDP we cannot have an empty payload type number list */ - /* as it happens only when mline is declined with a zero port, it does not matter to put whatever codec*/ - sdp_message_m_payload_add (msg,lineno, int_2char (0)); - } - switch(desc->dir){ - case SalStreamSendRecv: - /*dir="sendrecv";*/ - dir=NULL; - break; - case SalStreamRecvOnly: - dir="recvonly"; - break; - case SalStreamSendOnly: - dir="sendonly"; - break; - case SalStreamInactive: - dir="inactive"; - break; - } - if (dir) sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL); - if (rtp_port != 0) { - different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0); - if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) { - if (different_rtp_and_rtcp_addr == TRUE) { - char buffer[1024]; - snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); - sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), osip_strdup(buffer)); - } else { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("rtcp"), int_2char(rtcp_port)); - } - } - } - if (desc->ice_completed == TRUE) { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("nortpproxy"), osip_strdup("yes")); - } - if (desc->ice_mismatch == TRUE) { - sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-mismatch"), NULL); - } else { - if (desc->rtp_port != 0) { - if (desc->ice_pwd[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-pwd"), osip_strdup(desc->ice_pwd)); - if (desc->ice_ufrag[0] != '\0') sdp_message_a_attribute_add(msg, lineno, osip_strdup("ice-ufrag"), osip_strdup(desc->ice_ufrag)); - add_ice_candidates(msg, lineno, desc); - add_ice_remote_candidates(msg, lineno, desc); - } - } -} - - -sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){ - int i; - sdp_message_t *msg=create_generic_sdp(desc); - for(i=0;in_total_streams;++i){ - add_line(msg,i,&desc->streams[i]); - } - return msg; -} - -static int payload_type_fill_from_rtpmap(PayloadType *pt, const char *rtpmap){ - if (rtpmap==NULL){ - PayloadType *refpt=rtp_profile_get_payload(&av_profile,payload_type_get_number(pt)); - if (refpt){ - pt->mime_type=ms_strdup(refpt->mime_type); - pt->clock_rate=refpt->clock_rate; - }else{ - ms_error("payload number %i has no rtpmap and is unknown in AV Profile, ignored.", - payload_type_get_number(pt)); - return -1; - } - }else{ - char *mime=ms_strdup(rtpmap); - char *p=strchr(mime,'/'); - if (p){ - char *chans; - *p='\0'; - p++; - chans=strchr(p,'/'); - if (chans){ - *chans='\0'; - chans++; - pt->channels=atoi(chans); - }else pt->channels=1; - pt->clock_rate=atoi(p); - } - pt->mime_type=mime; - } - return 0; -} - -int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){ - int i,j; - const char *mtype,*proto,*rtp_port,*rtp_addr,*number; - const char *sess; - sdp_bandwidth_t *sbw=NULL; - sdp_attribute_t *attr; - int nb_ice_candidates; - - /* Get session information. */ - sess = sdp_message_o_sess_id_get(msg); - if (sess) desc->session_id = strtoul(sess, NULL, 10); - sess = sdp_message_o_sess_version_get(msg); - if (sess) desc->session_ver = strtoul(sess, NULL, 10); - - rtp_addr=sdp_message_c_addr_get (msg, -1, 0); - if (rtp_addr) - strncpy(desc->addr,rtp_addr,sizeof(desc->addr)); - for(j=0;(sbw=sdp_message_bandwidth_get(msg,-1,j))!=NULL;++j){ - if (strcasecmp(sbw->b_bwtype,"AS")==0) desc->bandwidth=atoi(sbw->b_bandwidth); - } - - /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ - for (i = 0; (i < SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES) && ((attr = sdp_message_attribute_get(msg, -1, i)) != NULL); i++) { - if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(desc->ice_ufrag, attr->a_att_value, sizeof(desc->ice_ufrag)); - } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(desc->ice_pwd, attr->a_att_value, sizeof(desc->ice_pwd)); - } else if (keywordcmp("ice-lite", attr->a_att_field) == 0) { - desc->ice_lite = TRUE; - } - } - - desc->n_active_streams = 0; - - /* for each m= line */ - for (i=0; !sdp_message_endof_media (msg, i) && istreams[i]; - nb_ice_candidates = 0; - - memset(stream,0,sizeof(*stream)); - mtype = sdp_message_m_media_get(msg, i); - proto = sdp_message_m_proto_get (msg, i); - rtp_port = sdp_message_m_port_get(msg, i); - stream->proto=SalProtoUnknown; - if (proto){ - if (strcasecmp(proto,"RTP/AVP")==0) - stream->proto=SalProtoRtpAvp; - else if (strcasecmp(proto,"RTP/SAVP")==0){ - stream->proto=SalProtoRtpSavp; - } - } - rtp_addr = sdp_message_c_addr_get (msg, i, 0); - if (rtp_addr != NULL) - strncpy(stream->rtp_addr,rtp_addr,sizeof(stream->rtp_addr)); - if (rtp_port) - stream->rtp_port=atoi(rtp_port); - if (stream->rtp_port > 0) - desc->n_active_streams++; - - stream->ptime=_sdp_message_get_a_ptime(msg,i); - 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); - } - for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){ - if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth); - } - stream->dir=_sdp_message_get_mline_dir(msg,i); - /* for each payload type */ - for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){ - const char *rtpmap,*fmtp; - int ptn=atoi(number); - PayloadType *pt=payload_type_new(); - payload_type_set_number(pt,ptn); - /* get the rtpmap associated to this codec, if any */ - rtpmap=sdp_message_a_attr_value_get_with_pt(msg, i,ptn,"rtpmap"); - if (payload_type_fill_from_rtpmap(pt,rtpmap)==0){ - /* get the fmtp, if any */ - fmtp=sdp_message_a_attr_value_get_with_pt(msg, i, ptn,"fmtp"); - payload_type_set_send_fmtp(pt,fmtp); - stream->payloads=ms_list_append(stream->payloads,pt); - ms_message("Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, - pt->send_fmtp ? pt->send_fmtp : ""); - } - } - - /* Get media specific RTCP attribute */ - stream->rtcp_port = stream->rtp_port + 1; - snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr); - for (j = 0; ((attr = sdp_message_attribute_get(msg, i, j)) != NULL); j++) { - if ((keywordcmp("rtcp", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - char tmp[256]; - int nb = sscanf(attr->a_att_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= line (%s) nb=%i", attr->a_att_value, nb); - } - } - } - - /* read crypto lines if any */ - if (stream->proto == SalProtoRtpSavp) { - int k, valid_count = 0; - - memset(&stream->crypto, 0, sizeof(stream->crypto)); - for (k=0;valid_count < SAL_CRYPTO_ALGO_MAX && (attr=sdp_message_attribute_get(msg,i,k))!=NULL;k++){ - char tmp[256], tmp2[256]; - if (keywordcmp("crypto",attr->a_att_field)==0 && attr->a_att_value!=NULL){ - int nb = sscanf(attr->a_att_value, "%d %255s inline:%255s", - &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 (strcmp(tmp, "AES_CM_128_HMAC_SHA1_80") == 0) - stream->crypto[valid_count].algo = AES_128_SHA1_80; - else if (strcmp(tmp, "AES_CM_128_HMAC_SHA1_32") == 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",attr->a_att_value,nb); - } - } - } - ms_message("Found: %d valid crypto lines", valid_count); - } - - /* Get ICE candidate attributes if any */ - for (j = 0; (attr = sdp_message_attribute_get(msg, i, j)) != NULL; j++) { - if ((keywordcmp("candidate", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; - int nb = sscanf(attr->a_att_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", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - SalIceRemoteCandidate candidate; - unsigned int componentID; - int offset; - char *ptr = attr->a_att_value; - 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[offset] == ' ') ptr += 1; - } - } else if ((keywordcmp("ice-ufrag", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(stream->ice_ufrag, attr->a_att_value, sizeof(stream->ice_ufrag)); - } else if ((keywordcmp("ice-pwd", attr->a_att_field) == 0) && (attr->a_att_value != NULL)) { - strncpy(stream->ice_pwd, attr->a_att_value, sizeof(stream->ice_pwd)); - } else if (keywordcmp("ice-mismatch", attr->a_att_field) == 0) { - stream->ice_mismatch = TRUE; - } - } - } - desc->n_total_streams=i; - return 0; -} diff --git a/coreapi/siplogin.c b/coreapi/siplogin.c index 6903638d6..c63d8af1e 100644 --- a/coreapi/siplogin.c +++ b/coreapi/siplogin.c @@ -66,7 +66,7 @@ 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); + auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL,NULL); linphone_core_add_auth_info(lc,auth); } linphone_proxy_config_enable_register(cfg,TRUE); @@ -113,10 +113,9 @@ SipSetup linphone_sip_login={ NULL, NULL, NULL, + sip_login_do_logout, NULL, - NULL, - NULL, - sip_login_do_logout + NULL }; diff --git a/coreapi/sipwizard.c b/coreapi/sipwizard.c index ee268e50c..c81dabf35 100644 --- a/coreapi/sipwizard.c +++ b/coreapi/sipwizard.c @@ -214,7 +214,7 @@ static int sip_wizard_do_login(SipSetupContext * ctx, const char *uri, const cha 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); + auth=linphone_auth_info_new(linphone_address_get_username(parsed_uri),NULL,passwd,NULL,NULL,NULL); linphone_core_add_auth_info(lc,auth); } linphone_proxy_config_enable_register(cfg,TRUE); diff --git a/coreapi/test_ecc.c b/coreapi/test_ecc.c index 38ba72765..8d383b625 100644 --- a/coreapi/test_ecc.c +++ b/coreapi/test_ecc.c @@ -21,6 +21,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "linphonecore_utils.h" +#if _MSC_VER +#include +#endif static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay, void *data){ ms_message("echo calibration finished %s.",status==LinphoneEcCalibratorDone ? "successfully" : "with faillure"); @@ -30,6 +33,9 @@ static void calibration_finished(LinphoneCore *lc, LinphoneEcCalibratorStatus st static char config_file[1024]; void parse_args(int argc, char *argv[]){ +#ifndef F_OK +#define F_OK 4 +#endif if (argc != 3 || strncmp("-c",argv[1], 2) || access(argv[2],F_OK)!=0) { printf("Usage: test_ecc [-c config_file] where config_file will be written with the detected value\n"); exit(-1); @@ -38,10 +44,11 @@ void parse_args(int argc, char *argv[]){ } int main(int argc, char *argv[]){ - if (argc>1) parse_args(argc,argv); int count=0; LinphoneCoreVTable vtable={0}; - LinphoneCore *lc=linphone_core_new(&vtable,config_file,NULL,NULL); + LinphoneCore *lc; + if (argc>1) parse_args(argc,argv); + lc=linphone_core_new(&vtable,config_file,NULL,NULL); linphone_core_enable_logs(NULL); diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 0922dad59..7b1307435 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -86,7 +86,8 @@ struct _UpnpContext { bool_t linphone_core_upnp_hook(void *data); -void linphone_core_upnp_refresh(UpnpContext *ctx); +void linphone_upnp_update(UpnpContext *ctx); +bool_t linphone_upnp_is_blacklisted(UpnpContext *ctx); UpnpPortBinding *linphone_upnp_port_binding_new(); UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port); @@ -198,6 +199,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { const char *ip_address = NULL; const char *connection_status = NULL; bool_t nat_enabled = FALSE; + bool_t blacklisted = FALSE; LinphoneUpnpState old_state; if(lupnp == NULL || lupnp->upnp_igd_ctxt == NULL) { @@ -217,6 +219,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { ip_address = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt); connection_status = upnp_igd_get_connection_status(lupnp->upnp_igd_ctxt); nat_enabled = upnp_igd_get_nat_enabled(lupnp->upnp_igd_ctxt); + blacklisted = linphone_upnp_is_blacklisted(lupnp); if(ip_address == NULL || connection_status == NULL) { ms_message("uPnP IGD: Pending"); @@ -224,11 +227,14 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { } else if(strcasecmp(connection_status, "Connected") || !nat_enabled) { ms_message("uPnP IGD: Not Available"); lupnp->state = LinphoneUpnpStateNotAvailable; + } else if(blacklisted) { + ms_message("uPnP IGD: Router is blacklisted"); + lupnp->state = LinphoneUpnpStateBlacklisted; } else { ms_message("uPnP IGD: Connected"); lupnp->state = LinphoneUpnpStateOk; if(old_state != LinphoneUpnpStateOk) { - linphone_core_upnp_refresh(lupnp); + linphone_upnp_update(lupnp); } } @@ -316,7 +322,12 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) { UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) { UpnpContext *lupnp = (UpnpContext *)ms_new0(UpnpContext,1); - + char address[LINPHONE_IPADDR_SIZE]; + const char*upnp_binding_address=address; + if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,NULL,address)) { + ms_warning("Linphone core [%p] cannot guess local address for upnp, let's choice the lib",lc); + upnp_binding_address=NULL; + } ms_mutex_init(&lupnp->mutex, NULL); ms_cond_init(&lupnp->empty_cond, NULL); @@ -328,7 +339,7 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) { lupnp->adding_configs = NULL; lupnp->removing_configs = NULL; lupnp->state = LinphoneUpnpStateIdle; - ms_message("uPnP IGD: New %p for core %p", lupnp, lc); + ms_message("uPnP IGD: New %p for core %p bound to %s", lupnp, lc,upnp_binding_address); // Init ports lupnp->sip_udp = NULL; @@ -338,7 +349,7 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) { linphone_core_add_iterate_hook(lc, linphone_core_upnp_hook, lupnp); lupnp->upnp_igd_ctxt = NULL; - lupnp->upnp_igd_ctxt = upnp_igd_create(linphone_upnp_igd_callback, linphone_upnp_igd_print, NULL, lupnp); + lupnp->upnp_igd_ctxt = upnp_igd_create(linphone_upnp_igd_callback, linphone_upnp_igd_print, address, lupnp); if(lupnp->upnp_igd_ctxt == NULL) { lupnp->state = LinphoneUpnpStateKo; ms_error("Can't create uPnP IGD context"); @@ -495,6 +506,45 @@ int linphone_upnp_context_get_external_port(UpnpContext *lupnp) { return port; } +bool_t linphone_upnp_is_blacklisted(UpnpContext *lupnp) { + const char * device_model_name = upnp_igd_get_device_model_name(lupnp->upnp_igd_ctxt); + const char * device_model_number = upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt); + const char * blacklist = lp_config_get_string(lupnp->lc->config, "net", "upnp_blacklist", NULL); + bool_t blacklisted = FALSE; + char *str; + char *pch; + char *model_name; + char *model_number; + + // Sanity checks + if(device_model_name == NULL || device_model_number == NULL || blacklist == NULL) { + return FALSE; + } + + // Find in the list + str = strdup(blacklist); + pch = strtok(str, ";"); + while (pch != NULL && !blacklisted) { + // Extract model name & number + model_name = pch; + model_number = strstr(pch, ","); + if(model_number != NULL) { + *(model_number++) = '\0'; + } + + // Compare with current device + if(strcmp(model_name, device_model_name) == 0) { + if(model_number == NULL || strcmp(model_number, device_model_number) == 0) { + blacklisted = TRUE; + } + } + pch = strtok(NULL, ";"); + } + free(str); + + return blacklisted; +} + void linphone_upnp_refresh(UpnpContext * lupnp) { upnp_igd_refresh(lupnp->upnp_igd_ctxt); } @@ -800,13 +850,24 @@ int linphone_upnp_call_process(LinphoneCall *call) { return ret; } -void linphone_core_upnp_refresh(UpnpContext *lupnp) { +static const char *linphone_core_upnp_get_charptr_null(const char *str) { + if(str != NULL) { + return str; + } + return "(Null)"; +} + +void linphone_upnp_update(UpnpContext *lupnp) { MSList *global_list = NULL; MSList *list = NULL; MSList *item; LinphoneCall *call; UpnpPortBinding *port_mapping, *port_mapping2; + ms_message("uPnP IGD: Name:%s", linphone_core_upnp_get_charptr_null(upnp_igd_get_device_name(lupnp->upnp_igd_ctxt))); + ms_message("uPnP IGD: Device:%s %s", + linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_name(lupnp->upnp_igd_ctxt)), + linphone_core_upnp_get_charptr_null(upnp_igd_get_device_model_number(lupnp->upnp_igd_ctxt))); ms_message("uPnP IGD: Refresh mappings"); if(lupnp->sip_udp != NULL) { diff --git a/coreapi/upnp.h b/coreapi/upnp.h index d785954a4..2239c896c 100644 --- a/coreapi/upnp.h +++ b/coreapi/upnp.h @@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/upnp_igd.h" #include "linphonecore.h" -#include "sal.h" +#include "sal/sal.h" typedef struct _UpnpSession UpnpSession; typedef struct _UpnpContext UpnpContext; diff --git a/gen-gtkfilelist.sh b/gen-gtkfilelist.sh index 15a5b8812..095c4979c 100755 --- a/gen-gtkfilelist.sh +++ b/gen-gtkfilelist.sh @@ -16,7 +16,6 @@ find share/locale/hu find share/locale/it find share/locale/ja find share/locale/nb -find share/locale/nb_NO find share/locale/nl find share/locale/pl find share/locale/pt @@ -24,7 +23,6 @@ find share/locale/pt_BR find share/locale/ru find share/locale/sr find share/locale/sv -find share/locale/zh find share/locale/zh_CN find share/locale/zh_TW find share/themes diff --git a/gtk+-2.24.8.filelist b/gtk+-2.24.8.filelist new file mode 100644 index 000000000..019823eae --- /dev/null +++ b/gtk+-2.24.8.filelist @@ -0,0 +1,202 @@ +bin +bin/freetype6.dll +bin/intl.dll +bin/libasprintf-0.dll +bin/libatk-1.0-0.dll +bin/libcairo-2.dll +bin/libcairo-gobject-2.dll +bin/libcairo-script-interpreter-2.dll +bin/libexpat-1.dll +bin/libfontconfig-1.dll +bin/libgailutil-18.dll +bin/libgcc_s_dw2-1.dll +bin/libgdk-win32-2.0-0.dll +bin/libgdk_pixbuf-2.0-0.dll +bin/libgio-2.0-0.dll +bin/libglib-2.0-0.dll +bin/libgmodule-2.0-0.dll +bin/libgobject-2.0-0.dll +bin/libgthread-2.0-0.dll +bin/libgtk-win32-2.0-0.dll +bin/libpango-1.0-0.dll +bin/libpangocairo-1.0-0.dll +bin/libpangoft2-1.0-0.dll +bin/libpangowin32-1.0-0.dll +bin/libpng14-14.dll +bin/zlib1.dll +lib/gtk-2.0 +lib/gtk-2.0/2.10.0 +lib/gtk-2.0/2.10.0/engines +lib/gtk-2.0/2.10.0/engines/libpixmap.dll +lib/gtk-2.0/2.10.0/engines/libwimp.dll +lib/gtk-2.0/include +lib/gtk-2.0/include/gdkconfig.h +lib/gtk-2.0/modules +lib/gtk-2.0/modules/libgail.dll +etc +etc/bash_completion.d +etc/bash_completion.d/gdbus-bash-completion.sh +etc/bash_completion.d/gsettings-bash-completion.sh +etc/fonts +etc/fonts/fonts.conf +etc/fonts/fonts.dtd +etc/gtk-2.0 +etc/gtk-2.0/gtk.immodules +etc/gtk-2.0/im-multipress.conf +etc/pango +etc/pango/pango.modules +share/locale/cs +share/locale/cs/LC_MESSAGES +share/locale/cs/LC_MESSAGES/atk10.mo +share/locale/cs/LC_MESSAGES/gdk-pixbuf.mo +share/locale/cs/LC_MESSAGES/gettext-runtime.mo +share/locale/cs/LC_MESSAGES/glib20.mo +share/locale/cs/LC_MESSAGES/gtk20-properties.mo +share/locale/cs/LC_MESSAGES/gtk20.mo +share/locale/de +share/locale/de/LC_MESSAGES +share/locale/de/LC_MESSAGES/atk10.mo +share/locale/de/LC_MESSAGES/gdk-pixbuf.mo +share/locale/de/LC_MESSAGES/gettext-runtime.mo +share/locale/de/LC_MESSAGES/glib20.mo +share/locale/de/LC_MESSAGES/gtk20-properties.mo +share/locale/de/LC_MESSAGES/gtk20.mo +share/locale/es +share/locale/es/LC_MESSAGES +share/locale/es/LC_MESSAGES/atk10.mo +share/locale/es/LC_MESSAGES/gdk-pixbuf.mo +share/locale/es/LC_MESSAGES/gettext-runtime.mo +share/locale/es/LC_MESSAGES/glib20.mo +share/locale/es/LC_MESSAGES/gtk20-properties.mo +share/locale/es/LC_MESSAGES/gtk20.mo +share/locale/fr +share/locale/fr/LC_MESSAGES +share/locale/fr/LC_MESSAGES/atk10.mo +share/locale/fr/LC_MESSAGES/gdk-pixbuf.mo +share/locale/fr/LC_MESSAGES/gettext-runtime.mo +share/locale/fr/LC_MESSAGES/glib20.mo +share/locale/fr/LC_MESSAGES/gtk20-properties.mo +share/locale/fr/LC_MESSAGES/gtk20.mo +share/locale/he +share/locale/he/LC_MESSAGES +share/locale/he/LC_MESSAGES/atk10.mo +share/locale/he/LC_MESSAGES/gdk-pixbuf.mo +share/locale/he/LC_MESSAGES/glib20.mo +share/locale/he/LC_MESSAGES/gtk20-properties.mo +share/locale/he/LC_MESSAGES/gtk20.mo +share/locale/hu +share/locale/hu/LC_MESSAGES +share/locale/hu/LC_MESSAGES/atk10.mo +share/locale/hu/LC_MESSAGES/gdk-pixbuf.mo +share/locale/hu/LC_MESSAGES/glib20.mo +share/locale/hu/LC_MESSAGES/gtk20-properties.mo +share/locale/hu/LC_MESSAGES/gtk20.mo +share/locale/it +share/locale/it/LC_MESSAGES +share/locale/it/LC_MESSAGES/atk10.mo +share/locale/it/LC_MESSAGES/gdk-pixbuf.mo +share/locale/it/LC_MESSAGES/gettext-runtime.mo +share/locale/it/LC_MESSAGES/glib20.mo +share/locale/it/LC_MESSAGES/gtk20-properties.mo +share/locale/it/LC_MESSAGES/gtk20.mo +share/locale/ja +share/locale/ja/LC_MESSAGES +share/locale/ja/LC_MESSAGES/atk10.mo +share/locale/ja/LC_MESSAGES/gdk-pixbuf.mo +share/locale/ja/LC_MESSAGES/gettext-runtime.mo +share/locale/ja/LC_MESSAGES/glib20.mo +share/locale/ja/LC_MESSAGES/gtk20-properties.mo +share/locale/ja/LC_MESSAGES/gtk20.mo +share/locale/nb +share/locale/nb/LC_MESSAGES +share/locale/nb/LC_MESSAGES/atk10.mo +share/locale/nb/LC_MESSAGES/gdk-pixbuf.mo +share/locale/nb/LC_MESSAGES/gettext-runtime.mo +share/locale/nb/LC_MESSAGES/glib20.mo +share/locale/nb/LC_MESSAGES/gtk20-properties.mo +share/locale/nb/LC_MESSAGES/gtk20.mo +share/locale/nl +share/locale/nl/LC_MESSAGES +share/locale/nl/LC_MESSAGES/atk10.mo +share/locale/nl/LC_MESSAGES/gdk-pixbuf.mo +share/locale/nl/LC_MESSAGES/gettext-runtime.mo +share/locale/nl/LC_MESSAGES/glib20.mo +share/locale/nl/LC_MESSAGES/gtk20-properties.mo +share/locale/nl/LC_MESSAGES/gtk20.mo +share/locale/pl +share/locale/pl/LC_MESSAGES +share/locale/pl/LC_MESSAGES/atk10.mo +share/locale/pl/LC_MESSAGES/gdk-pixbuf.mo +share/locale/pl/LC_MESSAGES/gettext-runtime.mo +share/locale/pl/LC_MESSAGES/glib20.mo +share/locale/pl/LC_MESSAGES/gtk20-properties.mo +share/locale/pl/LC_MESSAGES/gtk20.mo +share/locale/pt +share/locale/pt/LC_MESSAGES +share/locale/pt/LC_MESSAGES/atk10.mo +share/locale/pt/LC_MESSAGES/gdk-pixbuf.mo +share/locale/pt/LC_MESSAGES/gettext-runtime.mo +share/locale/pt/LC_MESSAGES/glib20.mo +share/locale/pt/LC_MESSAGES/gtk20-properties.mo +share/locale/pt/LC_MESSAGES/gtk20.mo +share/locale/pt_BR +share/locale/pt_BR/LC_MESSAGES +share/locale/pt_BR/LC_MESSAGES/atk10.mo +share/locale/pt_BR/LC_MESSAGES/gdk-pixbuf.mo +share/locale/pt_BR/LC_MESSAGES/gettext-runtime.mo +share/locale/pt_BR/LC_MESSAGES/glib20.mo +share/locale/pt_BR/LC_MESSAGES/gtk20-properties.mo +share/locale/pt_BR/LC_MESSAGES/gtk20.mo +share/locale/ru +share/locale/ru/LC_MESSAGES +share/locale/ru/LC_MESSAGES/atk10.mo +share/locale/ru/LC_MESSAGES/gdk-pixbuf.mo +share/locale/ru/LC_MESSAGES/gettext-runtime.mo +share/locale/ru/LC_MESSAGES/glib20.mo +share/locale/ru/LC_MESSAGES/gtk20-properties.mo +share/locale/ru/LC_MESSAGES/gtk20.mo +share/locale/sr +share/locale/sr/LC_MESSAGES +share/locale/sr/LC_MESSAGES/atk10.mo +share/locale/sr/LC_MESSAGES/gdk-pixbuf.mo +share/locale/sr/LC_MESSAGES/gettext-runtime.mo +share/locale/sr/LC_MESSAGES/glib20.mo +share/locale/sr/LC_MESSAGES/gtk20-properties.mo +share/locale/sr/LC_MESSAGES/gtk20.mo +share/locale/sv +share/locale/sv/LC_MESSAGES +share/locale/sv/LC_MESSAGES/atk10.mo +share/locale/sv/LC_MESSAGES/gdk-pixbuf.mo +share/locale/sv/LC_MESSAGES/gettext-runtime.mo +share/locale/sv/LC_MESSAGES/glib20.mo +share/locale/sv/LC_MESSAGES/gtk20-properties.mo +share/locale/sv/LC_MESSAGES/gtk20.mo +share/locale/zh_CN +share/locale/zh_CN/LC_MESSAGES +share/locale/zh_CN/LC_MESSAGES/atk10.mo +share/locale/zh_CN/LC_MESSAGES/gdk-pixbuf.mo +share/locale/zh_CN/LC_MESSAGES/gettext-runtime.mo +share/locale/zh_CN/LC_MESSAGES/glib20.mo +share/locale/zh_CN/LC_MESSAGES/gtk20-properties.mo +share/locale/zh_CN/LC_MESSAGES/gtk20.mo +share/locale/zh_TW +share/locale/zh_TW/LC_MESSAGES +share/locale/zh_TW/LC_MESSAGES/atk10.mo +share/locale/zh_TW/LC_MESSAGES/gdk-pixbuf.mo +share/locale/zh_TW/LC_MESSAGES/gettext-runtime.mo +share/locale/zh_TW/LC_MESSAGES/glib20.mo +share/locale/zh_TW/LC_MESSAGES/gtk20-properties.mo +share/locale/zh_TW/LC_MESSAGES/gtk20.mo +share/themes +share/themes/Default +share/themes/Default/gtk-2.0-key +share/themes/Default/gtk-2.0-key/gtkrc +share/themes/Emacs +share/themes/Emacs/gtk-2.0-key +share/themes/Emacs/gtk-2.0-key/gtkrc +share/themes/MS-Windows +share/themes/MS-Windows/gtk-2.0 +share/themes/MS-Windows/gtk-2.0/gtkrc +share/themes/Raleigh +share/themes/Raleigh/gtk-2.0 +share/themes/Raleigh/gtk-2.0/gtkrc diff --git a/gtk/Makefile.am b/gtk/Makefile.am index ba965b69a..b80527de0 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -61,7 +61,7 @@ linphone_LDADD= $(top_builddir)/coreapi/liblinphone.la \ if BUILD_WIN32 linphone.res: $(LINPHONE_ICO_RC_FILE) $(LINPHONE_ICO_FILE) - windres $(srcdir)/$(LINPHONE_ICO_RC_FILE) -O coff -o linphone.res + $(WINDRES) $(srcdir)/$(LINPHONE_ICO_RC_FILE) -O coff -o linphone.res linphone_LDADD+=linphone.res -lwininet linphone_LDFLAGS=-Wl,--export-all-symbols -mwindows diff --git a/gtk/buddylookup.c b/gtk/buddylookup.c index 55c3f334e..4a6cb8d7a 100644 --- a/gtk/buddylookup.c +++ b/gtk/buddylookup.c @@ -287,7 +287,7 @@ void linphone_gtk_add_buddy_from_database(GtkWidget *button){ gtk_tree_model_get (model, &iter,LOOKUP_RESULT_SIP_URI , &uri,LOOKUP_RESULT_NAME, &name, -1); addr=g_strdup_printf("%s <%s>",name,uri); - lf=linphone_friend_new_with_addr(addr); + lf=linphone_friend_new_with_address(addr); linphone_friend_set_inc_subscribe_policy(lf,presence ? LinphoneSPAccept : LinphoneSPDeny); linphone_friend_send_subscribe(lf,presence); linphone_core_add_friend(linphone_gtk_get_core(),lf); diff --git a/gtk/calllogs.c b/gtk/calllogs.c index 466541006..e9b460636 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -82,7 +82,7 @@ void linphone_gtk_call_log_add_contact(GtkWidget *w){ la=(LinphoneAddress*)pla; if (la!=NULL){ char *uri=linphone_address_as_string(la); - lf=linphone_friend_new_with_addr(uri); + lf=linphone_friend_new_with_address(uri); linphone_gtk_show_contact(lf); ms_free(uri); } diff --git a/gtk/chat.c b/gtk/chat.c index 13c140615..bfb6529e8 100644 --- a/gtk/chat.c +++ b/gtk/chat.c @@ -76,7 +76,7 @@ void linphone_gtk_quit_chatroom(LinphoneChatRoom *cr) { } g_hash_table_destroy(table); g_object_set_data(G_OBJECT(w),"cr",NULL); - g_object_set_data(G_OBJECT(friendlist),"from",NULL); + linphone_gtk_friend_list_set_active_address(NULL); gtk_widget_destroy(w); } @@ -178,7 +178,7 @@ void linphone_gtk_push_text(GtkWidget *w, const LinphoneAddress *from, case LinphoneChatMessageStateInProgress: { g_hash_table_insert(table,(gpointer)msg,GINT_TO_POINTER(gtk_text_iter_get_line(&iter))); - gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Sending .. ",-1, + gtk_text_buffer_insert_with_tags_by_name(buffer,&iter,"Sending ..",-1, "right","small","italic","font_grey","bg",NULL); g_object_set_data(G_OBJECT(w),"table",table); break; @@ -249,7 +249,7 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag switch (state) { case LinphoneChatMessageStateInProgress: - result="Sending "; + result="Sending .."; break; case LinphoneChatMessageStateDelivered: { @@ -258,16 +258,19 @@ void update_chat_state_message(LinphoneChatMessageState state,LinphoneChatMessag char buf[80]; strftime(buf,80,"%H:%M",tm); result=buf; + g_hash_table_remove(table,msg); break; } case LinphoneChatMessageStateNotDelivered: + { result="Message not sent"; + g_hash_table_remove(table,msg); break; + } default : result="Sending .."; } gtk_text_buffer_insert_with_tags_by_name(b,&iter,result,-1, "right","small","italic","font_grey","bg",NULL); - g_hash_table_remove(table,msg); g_object_set_data(G_OBJECT(page),"table",table); } } @@ -331,23 +334,24 @@ void display_history_message(GtkWidget *chat_view,MSList *messages,const Linphon void linphone_gtk_chat_add_contact(const LinphoneAddress *addr){ LinphoneFriend *lf=NULL; - char *uri=linphone_address_as_string(addr); - lf=linphone_friend_new_with_addr(uri); - ms_free(uri); - char *fixed_uri=NULL; + LinphoneAddress *fixed_uri=NULL; gboolean show_presence=FALSE; + char *uri=linphone_address_as_string(addr); + + lf=linphone_friend_new_with_address(uri); + ms_free(uri); linphone_friend_set_inc_subscribe_policy(lf,LinphoneSPDeny); linphone_friend_send_subscribe(lf,show_presence); - linphone_core_interpret_friend_uri(linphone_gtk_get_core(),uri,&fixed_uri); + fixed_uri = linphone_core_interpret_url(linphone_gtk_get_core(),uri); if (fixed_uri==NULL){ linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !")); return ; } - linphone_friend_set_addr(lf,addr); + linphone_friend_set_address(lf,addr); linphone_core_add_friend(linphone_gtk_get_core(),lf); - ms_free(fixed_uri); + linphone_address_destroy(fixed_uri); linphone_gtk_show_friends(); } @@ -463,12 +467,12 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, GtkWidget *w; gboolean send=TRUE; /*GtkNotebook *notebook= ( GtkNotebook * ) linphone_gtk_get_widget ( main_window,"viewswitch" );*/ - char *from=linphone_address_as_string ( linphone_chat_message_get_from ( msg ) ); + const LinphoneAddress *from= linphone_chat_message_get_from ( msg ); w= ( GtkWidget* ) g_object_get_data ( G_OBJECT ( friendlist ),"chatview" ); if ( w!=NULL ) { - char *from_chatview= ( char * ) g_object_get_data ( G_OBJECT ( friendlist ),"from" ); - if ( g_strcmp0 ( from,from_chatview ) ==0 ) { + const LinphoneAddress *from_chatview=linphone_gtk_friend_list_get_active_address(); + if (linphone_address_weak_equal(from,from_chatview)) { send=TRUE; } else { if ( !linphone_gtk_friend_list_is_contact ( linphone_chat_message_get_from ( msg ) ) ) { @@ -483,7 +487,7 @@ void linphone_gtk_text_received ( LinphoneCore *lc, LinphoneChatRoom *room, } w=linphone_gtk_init_chatroom ( room,linphone_chat_message_get_from ( msg ) ); g_object_set_data ( G_OBJECT ( friendlist ),"chatview", ( gpointer ) w ); - g_object_set_data ( G_OBJECT ( friendlist ),"from",from ); + linphone_gtk_friend_list_set_active_address(from); } #ifdef HAVE_GTK_OSX diff --git a/gtk/friendlist.c b/gtk/friendlist.c index 12da891f4..523cf13b3 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -197,9 +197,9 @@ void linphone_gtk_delete_history(GtkWidget *button){ gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); linphone_chat_room_delete_history(cr); if(chat_view!=NULL){ - char *from=g_object_get_data(G_OBJECT(friendlist),"from"); - char *addr=linphone_address_as_string(linphone_friend_get_address(lf)); - if(g_strcmp0(from,addr)==0){ + const LinphoneAddress *from=linphone_gtk_friend_list_get_active_address(); + const LinphoneAddress *addr=linphone_friend_get_address(lf); + if(linphone_address_weak_equal(from,addr)){ GtkTextView *text_view=GTK_TEXT_VIEW(linphone_gtk_get_widget(chat_view,"textview")); GtkTextIter start; GtkTextIter end; @@ -246,6 +246,20 @@ static gboolean grab_focus(GtkWidget *w){ return FALSE; } +void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr){ + GtkWidget *w=linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); + LinphoneAddress *old_addr=(LinphoneAddress*)g_object_get_data(G_OBJECT(friendlist),"from"); + g_object_set_data(G_OBJECT(friendlist),"from", addr ? linphone_address_clone(addr) : NULL); + if (old_addr) linphone_address_unref(old_addr); +} + +const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void){ + GtkWidget *w=linphone_gtk_get_main_window(); + GtkWidget *friendlist=linphone_gtk_get_widget(w,"contact_list"); + return (const LinphoneAddress*)g_object_get_data(G_OBJECT(friendlist),"from"); +} + void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){ GtkTreeIter iter; GtkListStore *store=NULL; @@ -256,12 +270,11 @@ void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){ LinphoneFriend *lf=NULL; LinphoneChatRoom *cr=NULL; GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(w,"viewswitch"); - char *la_str=linphone_address_as_string(la); - lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),la_str); + lf=linphone_core_find_friend(linphone_gtk_get_core(),la); if(lf==NULL){ cr=linphone_gtk_create_chatroom(la); - g_object_set_data(G_OBJECT(friendlist),"from",la_str); + linphone_gtk_friend_list_set_active_address(la); if(chat_view==NULL){ chat_view=linphone_gtk_init_chatroom(cr,la); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)chat_view); @@ -276,17 +289,15 @@ void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la){ if (gtk_tree_model_get_iter_first(model,&iter)) { do{ const LinphoneAddress *uri; - char *lf_str; gtk_tree_model_get(model, &iter,FRIEND_ID , &lf, -1); uri=linphone_friend_get_address(lf); - lf_str=linphone_address_as_string(uri); - if( g_strcmp0(lf_str,la_str)==0){ + if (linphone_address_weak_equal(uri,la)){ gtk_tree_model_get (model, &iter,FRIEND_CHATROOM , &cr, -1); if(cr==NULL){ cr=linphone_gtk_create_chatroom(uri); gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1); } - g_object_set_data(G_OBJECT(friendlist),"from",linphone_address_as_string(uri)); + linphone_gtk_friend_list_set_active_address(uri); if(chat_view==NULL){ chat_view=linphone_gtk_init_chatroom(cr,uri); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)chat_view); @@ -345,7 +356,7 @@ void linphone_gtk_chat_selected(GtkWidget *item){ gtk_list_store_set(store,&iter,FRIEND_CHATROOM,cr,-1); } page=(GtkWidget*)g_object_get_data(G_OBJECT(friendlist),"chatview"); - g_object_set_data(G_OBJECT(friendlist),"from",linphone_address_as_string(uri)); + linphone_gtk_friend_list_set_active_address(uri); if(page==NULL){ page=linphone_gtk_init_chatroom(cr,uri); g_object_set_data(G_OBJECT(friendlist),"chatview",(gpointer)page); @@ -442,19 +453,23 @@ void linphone_gtk_my_presence_clicked(GtkWidget *button){ static void icon_press_handler(GtkEntry *entry){ const char *text=gtk_entry_get_text(entry); if (text && strlen(text)>0){ - char *uri; + LinphoneAddress *addr; LinphoneFriend *lf; - linphone_core_interpret_friend_uri(linphone_gtk_get_core(),text,&uri); - if (uri==NULL){ + char *uri; + addr=linphone_core_interpret_url(linphone_gtk_get_core(),text); + if (addr==NULL){ return ; } + uri=linphone_address_as_string_uri_only(addr); lf=linphone_core_get_friend_by_address(linphone_gtk_get_core(),uri); + ms_free(uri); if (lf==NULL) - lf=linphone_friend_new_with_addr(uri); + lf=linphone_friend_new(); if (lf!=NULL){ + linphone_friend_set_address(lf,addr); linphone_gtk_show_contact(lf); } - ms_free(uri); + linphone_address_destroy(addr); } } @@ -476,11 +491,12 @@ static void check_contact(GtkEditable *editable, LinphoneCore *lc){ char *tmp=gtk_editable_get_chars(editable,0,-1); if (tmp!=NULL){ if (strlen(tmp)>0){ - char *uri=NULL; - linphone_core_interpret_friend_uri(lc,tmp,&uri); - if (uri){ + LinphoneAddress *addr=linphone_core_interpret_url(lc,tmp); + if (addr){ + char *uri=linphone_address_as_string_uri_only(addr); LinphoneFriend *lf=linphone_core_get_friend_by_address(lc,uri); ms_free(uri); + linphone_address_destroy(addr); if (lf) { update_star(GTK_ENTRY(editable),TRUE); g_free(tmp); @@ -862,7 +878,6 @@ void linphone_gtk_contact_ok(GtkWidget *button){ GtkWidget *w=gtk_widget_get_toplevel(button); LinphoneFriend *lf=(LinphoneFriend*)g_object_get_data(G_OBJECT(w),"friend_ref"); LinphoneFriend *lf2; - char *fixed_uri=NULL; gboolean show_presence=FALSE,allow_presence=FALSE; const gchar *name,*uri; LinphoneAddress* friend_address; @@ -879,28 +894,28 @@ void linphone_gtk_contact_ok(GtkWidget *button){ 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"))); - linphone_core_interpret_friend_uri(linphone_gtk_get_core(),uri,&fixed_uri); - if (fixed_uri==NULL){ + friend_address=linphone_core_interpret_url(linphone_gtk_get_core(),uri); + if (friend_address==NULL){ linphone_gtk_display_something(GTK_MESSAGE_WARNING,_("Invalid sip contact !")); return ; } - friend_address = linphone_address_new(fixed_uri); linphone_address_set_display_name(friend_address,name); - linphone_friend_set_addr(lf,friend_address); - linphone_address_destroy(friend_address); + 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)) { linphone_friend_done(lf); } else { - lf2=linphone_core_get_friend_by_address(linphone_gtk_get_core(),fixed_uri); + char *uri=linphone_address_as_string_uri_only(friend_address); + 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); } } - ms_free(fixed_uri); + linphone_address_destroy(friend_address); linphone_gtk_show_friends(); gtk_widget_destroy(w); } diff --git a/gtk/keypad.ui b/gtk/keypad.ui index 6b5376762..5dfcfc487 100644 --- a/gtk/keypad.ui +++ b/gtk/keypad.ui @@ -8,8 +8,11 @@ True False + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK 0.5 none + + True diff --git a/gtk/linphone.h b/gtk/linphone.h index f987b2abe..67fa27ebf 100644 --- a/gtk/linphone.h +++ b/gtk/linphone.h @@ -108,6 +108,8 @@ void linphone_gtk_text_received(LinphoneCore *lc, LinphoneChatRoom *room, Linpho void linphone_gtk_friend_list_update_chat_picture(); void linphone_gtk_friend_list_set_chat_conversation(const LinphoneAddress *la); gboolean linphone_gtk_friend_list_is_contact(const LinphoneAddress *addr); +void linphone_gtk_friend_list_set_active_address(const LinphoneAddress *addr); +const LinphoneAddress *linphone_gtk_friend_list_get_active_address(void); void linphone_gtk_notebook_tab_select(GtkNotebook *notebook,GtkWidget *page,guint page_num, gpointer data); void linphone_gtk_show_friends(void); void linphone_gtk_show_contact(LinphoneFriend *lf); diff --git a/gtk/loginframe.c b/gtk/loginframe.c index 08b90fe45..45da5480f 100644 --- a/gtk/loginframe.c +++ b/gtk/loginframe.c @@ -102,7 +102,7 @@ void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg){ linphone_address_set_username(from,username); } - ai=linphone_core_find_auth_info(lc,linphone_proxy_config_get_domain(cfg),linphone_address_get_username(from)); + ai=linphone_core_find_auth_info(lc,linphone_proxy_config_get_domain(cfg),linphone_address_get_username(from),NULL); /*display the last entered username, if not '?????'*/ if (linphone_address_get_username(from)[0]!='?') gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(mw,"login_username")), diff --git a/gtk/main.c b/gtk/main.c index 1aa2e287c..d8a8a2ede 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -34,6 +34,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef WIN32 #define chdir _chdir +#include "direct.h" #endif #if defined(HAVE_NOTIFY1) || defined(HAVE_NOTIFY4) @@ -54,7 +55,7 @@ static GtkWidget *the_ui=NULL; 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); +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_display_message(LinphoneCore *lc, const char *msg); static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning); @@ -63,6 +64,7 @@ static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl) static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg); static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token); static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate); +static void linphone_gtk_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data); static gboolean linphone_gtk_auto_answer(LinphoneCall *call); void linphone_gtk_status_icon_set_blinking(gboolean val); @@ -82,6 +84,7 @@ 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 GOptionEntry linphone_options[]={ { @@ -133,6 +136,13 @@ static GOptionEntry linphone_options[]={ .arg_data = (gpointer) & workingdir, .description = N_("Specifiy a working directory (should be the base of the installation, eg: c:\\Program Files\\Linphone)") }, + { + .long_name = "config", + .short_name = '\0', + .arg = G_OPTION_ARG_FILENAME, + .arg_data = (gpointer) &custom_config_file, + .description = N_("Configuration file") + }, {0} }; @@ -155,7 +165,9 @@ char *linphone_gtk_get_config_file(const char *filename){ /*try accessing a local file first if exists*/ if (access(CONFIG_FILE,F_OK)==0){ snprintf(config_file,path_max,"%s",filename); - }else{ + } else if (g_path_is_absolute(filename)) { + snprintf(config_file,path_max,"%s",filename); + } else{ #ifdef WIN32 const char *appdata=getenv("APPDATA"); if (appdata){ @@ -226,8 +238,8 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.call_state_changed=linphone_gtk_call_state_changed; vtable.registration_state_changed=linphone_gtk_registration_state_changed; - vtable.notify_presence_recv=linphone_gtk_notify_recv; - vtable.new_subscription_request=linphone_gtk_new_unknown_subscriber; + vtable.notify_presence_received=linphone_gtk_notify_recv; + vtable.new_subscription_requested=linphone_gtk_new_unknown_subscriber; vtable.auth_info_requested=linphone_gtk_auth_info_requested; vtable.display_status=linphone_gtk_display_status; vtable.display_message=linphone_gtk_display_message; @@ -240,14 +252,17 @@ static void linphone_gtk_init_liblinphone(const char *config_file, 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; the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); + 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); g_free(secrets_file); - linphone_core_enable_video(the_core,TRUE,TRUE); + linphone_core_enable_video_capture(the_core, TRUE); + linphone_core_enable_video_display(the_core, TRUE); if (no_video) { _linphone_gtk_enable_video(FALSE); linphone_gtk_set_ui_config_int("videoselfview",0); @@ -784,6 +799,9 @@ gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_ date, id); } + if (!dir) { + ms_message ("No directory for music, using [%s] instead",dir=getenv("HOME")); + } return g_build_filename(dir,filename,NULL); } @@ -874,7 +892,8 @@ void linphone_gtk_answer_clicked(GtkWidget *button){ void _linphone_gtk_enable_video(gboolean val){ LinphoneVideoPolicy policy={0}; policy.automatically_initiate=policy.automatically_accept=val; - linphone_core_enable_video(linphone_gtk_get_core(),TRUE,TRUE); + linphone_core_enable_video_capture(linphone_gtk_get_core(), TRUE); + linphone_core_enable_video_display(linphone_gtk_get_core(), TRUE); linphone_core_set_video_policy(linphone_gtk_get_core(),&policy); if (val){ @@ -1007,7 +1026,7 @@ void linphone_gtk_password_ok(GtkWidget *w){ gtk_widget_destroy(window); } -static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username){ +static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain){ GtkWidget *w=linphone_gtk_create_window("password"); GtkWidget *label=linphone_gtk_get_widget(w,"message"); LinphoneAuthInfo *info; @@ -1020,18 +1039,22 @@ static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm return; } - msg=g_strdup_printf(_("Please enter your password for username %s\n at domain %s:"), + msg=g_strdup_printf(_("Please enter your password for username %s\n at realm %s:"), username,realm); gtk_label_set_markup(GTK_LABEL(label),msg); g_free(msg); gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"userid_entry")),username); - info=linphone_auth_info_new(username, NULL, NULL, NULL,realm); + info=linphone_auth_info_new(username, NULL, NULL, NULL,realm,domain); g_object_set_data(G_OBJECT(w),"auth_info",info); g_object_weak_ref(G_OBJECT(w),(GWeakNotify)linphone_auth_info_destroy,info); gtk_widget_show(w); auth_timeout_new(w); } +static void linphone_gtk_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf){ + ms_message("Dtmf %c received.",dtmf); +} + static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){ GtkWidget *w=linphone_gtk_get_main_window(); GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar"); @@ -1698,6 +1721,40 @@ void linphone_gtk_init_dtmf_table(GtkWidget *mw){ g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*"); } +static gboolean key_allowed(guint32 code){ + static const char *allowed="1234567890#*ABCD"; + return code!=0 && strchr(allowed,(char)code)!=NULL; +} + +static GtkButton *get_button_from_key(GtkWidget *w, GdkEvent *event){ + guint keyval=event->key.keyval; + guint32 code=gdk_keyval_to_unicode(keyval); + code=g_unichar_toupper(code); + if (key_allowed(code)){ + char widgetname[16]; + w=gtk_widget_get_toplevel(w); + snprintf(widgetname,sizeof(widgetname),"dtmf_%c",code); + return GTK_BUTTON(linphone_gtk_get_widget(w,widgetname)); + } + return NULL; +} + +void linphone_gtk_keypad_key_pressed(GtkWidget *w, GdkEvent *event, gpointer userdata){ + GtkButton *button=get_button_from_key(w,event); + if (button) { + linphone_gtk_dtmf_pressed(button); + /*g_signal_emit_by_name(button, "button-press-event");*/ + } +} + +void linphone_gtk_keypad_key_released(GtkWidget *w, GdkEvent *event, gpointer userdata){ + GtkButton *button=get_button_from_key(w,event); + if (button) { + linphone_gtk_dtmf_released(button); + /*g_signal_emit_by_name(button, "button-release-event");*/ + } +} + void linphone_gtk_create_keypad(GtkWidget *button){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad"); @@ -1913,6 +1970,14 @@ int main(int argc, char *argv[]){ gdk_threads_leave(); return -1; } + if (config_file) free(config_file); + if (custom_config_file && !g_path_is_absolute(custom_config_file)) { + gchar *res = g_get_current_dir(); + res = g_strjoin(G_DIR_SEPARATOR_S, res, custom_config_file, NULL); + free(custom_config_file); + custom_config_file = res; + } + config_file=linphone_gtk_get_config_file(custom_config_file); settings=gtk_settings_get_default(); g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM)); diff --git a/gtk/main.ui b/gtk/main.ui index dde462ec3..ae1335c5d 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -1548,6 +1548,7 @@ True + True True False none diff --git a/gtk/parameters.ui b/gtk/parameters.ui index b8063792f..4cb435eb2 100644 --- a/gtk/parameters.ui +++ b/gtk/parameters.ui @@ -48,6 +48,12 @@ 1 9.9999999995529656 + + 65535 + 5060 + 1 + 10 + 65535 2 @@ -324,23 +330,10 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 7 + 8 2 - - True - False - model8 - - - - 0 - - - - - - + True True @@ -350,6 +343,7 @@ True True adjustment7 + 1 @@ -363,8 +357,8 @@ Media encryption type - 3 - 5 + 4 + 6 @@ -376,24 +370,8 @@ 1 2 - 3 - 4 - - - - - gtk-edit - True - True - False - True - - - - 1 - 2 - 6 - 7 + 4 + 5 @@ -405,8 +383,8 @@ right - 2 - 3 + 3 + 4 @@ -418,36 +396,8 @@ right - 1 - 2 - - - - - True - False - DSCP fields - - - 5 - 6 - - - - - gtk-edit - True - True - True - False - True - - - - 1 - 2 - 5 - 6 + 2 + 3 @@ -513,8 +463,8 @@ 1 2 - 1 - 2 + 2 + 3 @@ -580,18 +530,8 @@ 1 2 - 2 - 3 - - - - - False - Tunnel - - - 6 - 7 + 3 + 4 @@ -607,10 +547,102 @@ 1 2 - 4 - 5 + 5 + 6 + + + False + Tunnel + + + 7 + 8 + + + + + gtk-edit + True + True + False + True + + + + 1 + 2 + 7 + 8 + + + + + True + False + DSCP fields + + + 6 + 7 + + + + + gtk-edit + True + True + True + False + True + + + + 1 + 2 + 6 + 7 + + + + + True + False + SIP/TCP port + + + 1 + 2 + + + + + True + True + + True + False + False + True + True + adjustment8 + + + + 1 + 2 + 1 + 2 + + + + + True + False + SIP/UDP port + + @@ -1173,7 +1205,7 @@ True False - 2 + 3 2 @@ -1237,6 +1269,39 @@ 2 + + + True + False + Video output method: + right + + + 2 + 3 + GTK_EXPAND + + + + + True + False + + + + + 0 + + + + + 1 + 2 + 2 + 3 + GTK_EXPAND + + diff --git a/gtk/propertybox.c b/gtk/propertybox.c index f30b55d05..8579fc2f4 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -28,21 +28,35 @@ typedef enum { static void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const char *selected, DeviceCap cap){ const char **p=devices; - int i=0,active=0; - /* glade creates a combo box without list model and text renderer, - unless we fill it with a dummy text. - This dummy text needs to be removed first*/ - gtk_combo_box_remove_text(GTK_COMBO_BOX(combo),0); + int i=0,active=-1; + GtkTreeModel *model; + + + if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){ + /*case where combo box is created with no model*/ + GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); + model=GTK_TREE_MODEL(gtk_list_store_new(1,G_TYPE_STRING)); + gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",0,NULL); + }else{ + gtk_list_store_clear(GTK_LIST_STORE(model)); + /* glade creates a combo box without list model and text renderer, + unless we fill it with a dummy text. + This dummy text needs to be removed first*/ + } + for(;*p!=NULL;++p){ if ( cap==CAP_IGNORE || (cap==CAP_CAPTURE && linphone_core_sound_device_can_capture(linphone_gtk_get_core(),*p)) || (cap==CAP_PLAYBACK && linphone_core_sound_device_can_playback(linphone_gtk_get_core(),*p)) ){ gtk_combo_box_append_text(GTK_COMBO_BOX(combo),*p); - if (strcmp(selected,*p)==0) active=i; + if (selected && strcmp(selected,*p)==0) active=i; i++; } } - gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); + if (active!=-1) + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); } void linphone_gtk_fill_video_sizes(GtkWidget *combo){ @@ -79,7 +93,7 @@ void linphone_gtk_update_my_contact(GtkWidget *w){ linphone_address_set_display_name(parsed,displayname); linphone_address_set_username(parsed,username); - linphone_address_set_port_int(parsed,port); + linphone_address_set_port(parsed,port); contact=linphone_address_as_string(parsed); gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"sip_address")),contact); linphone_core_set_primary_contact(linphone_gtk_get_core(),contact); @@ -88,49 +102,6 @@ void linphone_gtk_update_my_contact(GtkWidget *w){ linphone_gtk_load_identities(); } -void linphone_gtk_update_my_port(GtkWidget *w){ - GtkWidget *pb=gtk_widget_get_toplevel(GTK_WIDGET(w)); - LCSipTransports tr; - LinphoneCore *lc=linphone_gtk_get_core(); - GtkComboBox *combo = GTK_COMBO_BOX(linphone_gtk_get_widget(pb, "proto_combo")); - - gint port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); - if (port == 1) { // We use default port if not specified - if (strcmp(gtk_combo_box_get_active_text(combo), "SIP (UDP)") == 0) { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), - 5060); - } - else if (strcmp(gtk_combo_box_get_active_text(combo), "SIP (TCP)") == 0) { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), - 5060); - } - else if (strcmp(gtk_combo_box_get_active_text(combo), "SIP (TLS)") == 0) { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), - 5061); - } - } - - linphone_core_get_sip_transports(lc,&tr); - gchar *selected = gtk_combo_box_get_active_text(combo); - if (strcmp(selected, "SIP (TCP)") == 0) { - tr.tcp_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); - tr.udp_port = 0; - tr.tls_port = 0; - } - else if (strcmp(gtk_combo_box_get_active_text(GTK_COMBO_BOX(linphone_gtk_get_widget(pb, "proto_combo"))), "SIP (UDP)") == 0) { - tr.udp_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); - tr.tcp_port = 0; - tr.tls_port = 0; - } - else if (strcmp(gtk_combo_box_get_active_text(GTK_COMBO_BOX(linphone_gtk_get_widget(pb, "proto_combo"))), "SIP (TLS)") == 0){ - tr.udp_port = 0; - tr.tcp_port = 0; - tr.tls_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)); - } - - linphone_core_set_sip_transports(lc,&tr); -} - void linphone_gtk_set_propety_entry(GtkWidget *w, gboolean stunServer, gboolean ip){ GtkWidget *stun_entry=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"stun_server"); GtkWidget *ip_entry=linphone_gtk_get_widget(gtk_widget_get_toplevel(w),"nat_address"); @@ -317,6 +288,16 @@ void linphone_gtk_video_size_changed(GtkWidget *w){ defs[sel].vsize); } +void linphone_gtk_video_renderer_changed(GtkWidget *w){ + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w),&iter)){ + GtkTreeModel *model=gtk_combo_box_get_model(GTK_COMBO_BOX(w)); + gchar *name; + gtk_tree_model_get(model,&iter,0,&name,-1); + linphone_core_set_video_display_filter(linphone_gtk_get_core(),name); + } +} + void linphone_gtk_ring_file_set(GtkWidget *w){ gchar *file=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(w)); linphone_core_set_ring(linphone_gtk_get_core(),file); @@ -399,7 +380,7 @@ static void linphone_gtk_init_codec_list(GtkTreeView *listview){ "foreground",CODEC_COLOR, NULL); gtk_tree_view_append_column (listview, column); - column = gtk_tree_view_column_new_with_attributes (_("Min bitrate (kbit/s)"), + column = gtk_tree_view_column_new_with_attributes (_("Bitrate (kbit/s)"), renderer, "text", CODEC_BITRATE, "foreground",CODEC_COLOR, @@ -667,6 +648,77 @@ static void linphone_gtk_proxy_closed(GtkWidget *w){ } } +static void fill_transport_combo_box(GtkWidget *combo, LinphoneTransportType choice, gboolean is_sensitive){ + GtkTreeModel *model; + GtkTreeIter iter; + + if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(combo),"combo-updating"))) return; + + if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){ + /*case where combo box is created with no model*/ + GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); + model=GTK_TREE_MODEL(gtk_list_store_new(1,G_TYPE_STRING)); + gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"markup",0,NULL); + } + if (!gtk_tree_model_get_iter_first(model,&iter)){ + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,"UDP",-1); + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,"TCP",-1); + if (linphone_core_sip_transport_supported(linphone_gtk_get_core(),LinphoneTransportTls)){ + gtk_list_store_append(GTK_LIST_STORE(model),&iter); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,"TLS",-1); + } + } + gtk_combo_box_set_active(GTK_COMBO_BOX(combo),(int)choice); + gtk_widget_set_sensitive(combo,is_sensitive); +} + +static void update_proxy_transport(GtkWidget *w){ + const char *addr=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy"))); + LinphoneAddress *laddr=linphone_address_new(addr); + if (laddr){ + GtkWidget *combo=linphone_gtk_get_widget(w,"transport"); + if (linphone_address_is_secure(laddr)){ + fill_transport_combo_box(combo,LinphoneTransportTls,FALSE); + }else{ + fill_transport_combo_box(combo,linphone_address_get_transport(laddr),TRUE); + } + linphone_address_destroy(laddr); + } +} + +void linphone_gtk_proxy_transport_changed(GtkWidget *combo){ + GtkWidget *w=gtk_widget_get_toplevel(combo); + int index=gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); + GtkWidget *proxy=linphone_gtk_get_widget(w,"proxy"); + const char *addr=gtk_entry_get_text(GTK_ENTRY(proxy)); + LinphoneAddress *laddr; + LinphoneTransportType new_transport=(LinphoneTransportType)index; + + if (index==-1) return; + + g_object_set_data(G_OBJECT(w),"combo-updating",GINT_TO_POINTER(1)); + laddr=linphone_address_new(addr); + if (laddr){ + if (linphone_address_get_transport(laddr)!=new_transport){ + char *newaddr; + linphone_address_set_transport(laddr,new_transport); + newaddr=linphone_address_as_string(laddr); + gtk_entry_set_text(GTK_ENTRY(proxy),newaddr); + ms_free(newaddr); + } + linphone_address_destroy(laddr); + } + g_object_set_data(G_OBJECT(w),"combo-updating",GINT_TO_POINTER(0)); +} + +void linphone_gtk_proxy_address_changed(GtkEditable *editable){ + update_proxy_transport(gtk_widget_get_toplevel(GTK_WIDGET(editable))); +} + void linphone_gtk_show_proxy_config(GtkWidget *pb, LinphoneProxyConfig *cfg){ GtkWidget *w=linphone_gtk_create_window("sip_account"); const char *tmp; @@ -674,10 +726,11 @@ void linphone_gtk_show_proxy_config(GtkWidget *pb, LinphoneProxyConfig *cfg){ linphone_proxy_config_edit(cfg); gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"identity")), linphone_proxy_config_get_identity(cfg)); - gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")), - linphone_proxy_config_get_addr(cfg)); + gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")),linphone_proxy_config_get_addr(cfg)); tmp=linphone_proxy_config_get_route(cfg); if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")),tmp); + tmp=linphone_proxy_config_get_contact_parameters(cfg); + if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(w,"params")),tmp); gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"regperiod")), linphone_proxy_config_get_expires(cfg)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")), @@ -697,20 +750,41 @@ void linphone_gtk_proxy_cancel(GtkButton *button){ } void linphone_gtk_proxy_ok(GtkButton *button){ + LinphoneCore *lc=linphone_gtk_get_core(); GtkWidget *w=gtk_widget_get_toplevel(GTK_WIDGET(button)); LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)g_object_get_data(G_OBJECT(w),"config"); + int index=gtk_combo_box_get_active(GTK_COMBO_BOX(linphone_gtk_get_widget(w,"transport"))); + LinphoneTransportType tport=(LinphoneTransportType)index; gboolean was_editing=TRUE; + if (!cfg){ was_editing=FALSE; cfg=linphone_proxy_config_new(); } linphone_proxy_config_set_identity(cfg, gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"identity")))); - linphone_proxy_config_set_server_addr(cfg, - gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy")))); + if (linphone_proxy_config_set_server_addr(cfg, + gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"proxy"))))==0){ + if (index!=-1){ + /*make sure transport was added to proxy address*/ + LinphoneAddress *laddr=linphone_address_new(linphone_proxy_config_get_addr(cfg)); + if (laddr){ + if (linphone_address_get_transport(laddr)!=tport){ + char *tmp; + linphone_address_set_transport(laddr,tport); + tmp=linphone_address_as_string(laddr); + linphone_proxy_config_set_server_addr(cfg,tmp); + ms_free(tmp); + } + linphone_address_destroy(laddr); + } + } + } linphone_proxy_config_set_route(cfg, gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"route")))); - linphone_proxy_config_expires(cfg, + linphone_proxy_config_set_contact_parameters(cfg, + gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"params")))); + linphone_proxy_config_set_expires(cfg, (int)gtk_spin_button_get_value( GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"regperiod")))); linphone_proxy_config_enable_publish(cfg, @@ -719,6 +793,17 @@ void linphone_gtk_proxy_ok(GtkButton *button){ linphone_proxy_config_enable_register(cfg, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")))); + + /* check if tls was asked but is not enabled in transport configuration*/ + if (tport==LinphoneTransportTls){ + LCSipTransports tports; + linphone_core_get_sip_transports(lc,&tports); + if (tports.tls_port==LC_SIP_TRANSPORT_DISABLED){ + tports.tls_port=LC_SIP_TRANSPORT_RANDOM; + } + linphone_core_set_sip_transports(lc,&tports); + } + if (was_editing){ if (linphone_proxy_config_done(cfg)==-1) return; @@ -873,14 +958,6 @@ void linphone_gtk_lang_changed(GtkComboBox *combo){ } } -void linphone_gtk_proto_changed(GtkComboBox *combo){ - GtkWidget *pb=gtk_widget_get_toplevel(GTK_WIDGET(combo)); - - GtkWidget *proto_port = linphone_gtk_get_widget(pb, "proto_port"); - // When we change the network protocol, we call update_my_port to move the port number from the old protocol to the new one - linphone_gtk_update_my_port(proto_port); -} - static void linphone_gtk_ui_level_adapt(GtkWidget *top) { gboolean ui_advanced; const char *simple_ui = linphone_gtk_get_ui_config("simple_ui", "parameters.codec_tab parameters.transport_frame parameters.ports_frame"); @@ -997,7 +1074,6 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){ void linphone_gtk_parameters_destroyed(GtkWidget *pb){ GtkWidget *mw=linphone_gtk_get_main_window(); - ms_error("linphone_gtk_paramters_destroyed"); g_object_set_data(G_OBJECT(mw),"parameters",NULL); } @@ -1018,6 +1094,78 @@ void linphone_gtk_fill_webcams(GtkWidget *pb){ linphone_core_get_video_device(lc),CAP_IGNORE); } +void linphone_gtk_fill_video_renderers(GtkWidget *pb){ + LinphoneCore *lc=linphone_gtk_get_core(); + GtkWidget *combo=linphone_gtk_get_widget(pb,"renderers"); + MSList *l=ms_filter_lookup_by_interface(MSFilterVideoDisplayInterface); + MSList *elem; + int i; + int active=-1; + const char *current_renderer=linphone_core_get_video_display_filter(lc); + GtkListStore *store; + GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); + GtkTreeModel *model=GTK_TREE_MODEL(store=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_STRING)); + + gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); + gtk_cell_layout_clear(GTK_CELL_LAYOUT(combo)); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",1,NULL); + + for(i=0,elem=l;elem!=NULL && i<4 ;elem=elem->next,++i){ + MSFilterDesc *desc=(MSFilterDesc *)elem->data; + GtkTreeIter iter; + gtk_list_store_append(store,&iter); + gtk_list_store_set(store,&iter,0,desc->name,1,desc->text,-1); + if (current_renderer && strcmp(current_renderer,desc->name)==0) + active=i; + } + ms_list_free(l); + if (active!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); +} + +typedef struct { + guint timeout_id; + LCSipTransports tp; +}PortConfigCtx; + +static void port_config_free(PortConfigCtx *ctx){ + g_free(ctx); +} + +static gboolean apply_transports(PortConfigCtx *ctx){ + GtkWidget *mw=linphone_gtk_get_main_window(); + LCSipTransports tp; + LinphoneCore *lc=linphone_gtk_get_core(); + linphone_core_get_sip_transports(lc,&tp); + tp.udp_port=ctx->tp.udp_port; + tp.tcp_port=ctx->tp.tcp_port; + linphone_core_set_sip_transports(lc,&tp); + g_object_set_data(G_OBJECT(mw),"port_config",NULL); + return FALSE; +} + +static void transport_changed(GtkWidget *parameters){ + GtkWidget *mw=linphone_gtk_get_main_window(); + PortConfigCtx *cfg=(PortConfigCtx*)g_object_get_data(G_OBJECT(mw),"port_config"); + if (cfg==NULL){ + cfg=g_new0(PortConfigCtx,1); + g_object_set_data_full(G_OBJECT(mw),"port_config",cfg,(GDestroyNotify)port_config_free); + } + if (cfg->timeout_id!=0) + g_source_remove(cfg->timeout_id); + cfg->tp.udp_port=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(linphone_gtk_get_widget(parameters,"sip_udp_port"))); + cfg->tp.tcp_port=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(linphone_gtk_get_widget(parameters,"sip_tcp_port"))); + cfg->timeout_id=g_timeout_add_seconds(2,(GSourceFunc)apply_transports,cfg); +} + +void linphone_gtk_udp_port_value_changed(GtkSpinButton *button){ + transport_changed(gtk_widget_get_toplevel((GtkWidget*)button)); +} + +void linphone_gtk_tcp_port_value_changed(GtkSpinButton *button){ + transport_changed(gtk_widget_get_toplevel((GtkWidget*)button)); +} + void linphone_gtk_show_parameters(void){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *pb=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"parameters"); @@ -1045,21 +1193,11 @@ void linphone_gtk_show_parameters(void){ linphone_core_ipv6_enabled(lc)); linphone_core_get_sip_transports(lc,&tr); - if (tr.tcp_port > 0) { - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 1); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")), - tr.tcp_port); - } - else if (tr.tls_port > 0) { - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 2); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")), - tr.tls_port); - } - else { - gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 0); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")), + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_udp_port")), tr.udp_port); - } + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_tcp_port")), + tr.tcp_port); + linphone_core_get_audio_port_range(lc, &min_port, &max_port); gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")), min_port); @@ -1100,7 +1238,7 @@ void linphone_gtk_show_parameters(void){ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_upnp")),TRUE); break; } - if(!linphone_core_upnp_available(lc)) { + if(!linphone_core_upnp_available()) { gtk_widget_hide(linphone_gtk_get_widget(pb,"use_upnp")); } @@ -1119,7 +1257,7 @@ void linphone_gtk_show_parameters(void){ /* MUTIMEDIA CONFIG */ linphone_gtk_fill_soundcards(pb); linphone_gtk_fill_webcams(pb); - + linphone_gtk_fill_video_renderers(pb); linphone_gtk_fill_video_sizes(linphone_gtk_get_widget(pb,"video_size")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"echo_cancelation")), linphone_core_echo_cancellation_enabled(lc)); @@ -1158,10 +1296,6 @@ void linphone_gtk_show_parameters(void){ ui_advanced); linphone_gtk_ui_level_adapt(pb); - g_signal_connect(G_OBJECT(linphone_gtk_get_widget(pb,"proto_port")),"value-changed",(GCallback)linphone_gtk_update_my_port,NULL); - g_signal_connect(G_OBJECT(linphone_gtk_get_widget(pb,"proto_combo")),"changed",(GCallback)linphone_gtk_proto_changed,NULL); - - if (linphone_core_tunnel_available()){ gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_edit_button")), TRUE); gtk_widget_set_visible(GTK_WIDGET(linphone_gtk_get_widget(pb,"tunnel_label")), TRUE); @@ -1202,8 +1336,8 @@ void linphone_gtk_fixed_video_port_toggle(void) { void linphone_gtk_edit_tunnel_closed(GtkWidget *button){ - GtkWidget *pb=gtk_widget_get_toplevel(button); - gtk_widget_destroy(pb); + GtkWidget *pb=gtk_widget_get_toplevel(button); + gtk_widget_destroy(pb); } void linphone_gtk_edit_tunnel(GtkButton *button){ diff --git a/gtk/setupwizard.c b/gtk/setupwizard.c index 439f9c89f..afb543a85 100644 --- a/gtk/setupwizard.c +++ b/gtk/setupwizard.c @@ -59,7 +59,7 @@ static int all_account_information_entered(GtkWidget *w) { if (gtk_entry_get_text_length(username) > 0 && gtk_entry_get_text_length(domain) > 0 && - g_regex_match_simple("^[a-zA-Z]+[a-zA-Z0-9.\\-_]{2,}$", gtk_entry_get_text(username), 0, 0) && + g_regex_match_simple("^[a-zA-Z0-9]+[a-zA-Z0-9.\\-_]{2,}$", gtk_entry_get_text(username), 0, 0) && g_regex_match_simple("^(sip:)?([a-zA-Z0-9]+([\\.-][a-zA-Z0-9]+)*)$", gtk_entry_get_text(domain), 0, 0)) { return 1; } @@ -416,7 +416,7 @@ static void linphone_gtk_assistant_prepare(GtkWidget *assistant, GtkWidget *page linphone_proxy_config_set_identity(cfg, creator->username); linphone_proxy_config_set_server_addr(cfg, creator->domain); linphone_proxy_config_set_route(cfg, creator->route); - linphone_proxy_config_expires(cfg, 3600); + linphone_proxy_config_set_expires(cfg, 3600); linphone_proxy_config_enable_publish(cfg, FALSE); linphone_proxy_config_enable_register(cfg, TRUE); @@ -430,7 +430,7 @@ static void linphone_gtk_assistant_prepare(GtkWidget *assistant, GtkWidget *page } gchar domain[128]; g_snprintf(domain, sizeof(domain), "\"%s\"", creator->domain + 4); - LinphoneAuthInfo *info=linphone_auth_info_new(username, username, creator->password, NULL, domain); + LinphoneAuthInfo *info=linphone_auth_info_new(username, username, creator->password, NULL, NULL, domain); linphone_core_add_auth_info(linphone_gtk_get_core(),info); g_free(username); diff --git a/gtk/sip_account.ui b/gtk/sip_account.ui index 60b751cfa..d0a93d5dc 100644 --- a/gtk/sip_account.ui +++ b/gtk/sip_account.ui @@ -1,6 +1,7 @@ + 100000 3600 @@ -15,13 +16,13 @@ center-on-parent dialog - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 2 - + True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -91,7 +92,7 @@ True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 4 + 6 2 @@ -112,6 +113,8 @@ sip: False False + True + True 1 @@ -140,6 +143,9 @@ sip: False False + True + True + 1 @@ -148,19 +154,6 @@ 2 - - - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Route (optional): - right - - - 2 - 3 - - True @@ -168,12 +161,14 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True 1 2 - 2 - 3 + 4 + 5 @@ -185,8 +180,8 @@ right - 3 - 4 + 2 + 3 @@ -196,8 +191,80 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False + True + True adjustment1 + + 1 + 2 + 2 + 3 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Contact params (optional): + right + + + 5 + 6 + + + + + 275 + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + True + False + False + True + True + + + 1 + 2 + 5 + 6 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Route (optional): + right + + + 4 + 5 + + + + + True + False + Transport + + + 3 + 4 + + + + + True + False + + 1 2 diff --git a/gtk/update.c b/gtk/update.c index 6fac1b8ff..34cff9995 100644 --- a/gtk/update.c +++ b/gtk/update.c @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include -static int linphone_gtk_get_new_version(const char *version_url, char *version, size_t size){ +static int linphone_gtk_create_version(const char *version_url, char *version, size_t size){ DWORD dwDownloaded = 0; HINTERNET hSession = NULL, hConnect = NULL; int ret=-1; @@ -55,7 +55,7 @@ static int linphone_gtk_get_new_version(const char *version_url, char *version, #else -static int linphone_gtk_get_new_version(const char *url, char *version, size_t size){ +static int linphone_gtk_create_version(const char *url, char *version, size_t size){ return -1; } @@ -121,7 +121,7 @@ static int version_compare(const char *v1, const char *v2){ static void *check_for_new_version(void *d){ const char *version_url=(const char *)d; char version[256]; - if (linphone_gtk_get_new_version(version_url,version,sizeof(version))==0){ + if (linphone_gtk_create_version(version_url,version,sizeof(version))==0){ if (version_compare(version,LINPHONE_VERSION)>0){ const char *download_site=linphone_gtk_get_ui_config("download_site",NULL); if (download_site) { diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100755 index 000000000..0c6cc77b0 --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST=sal/sal.h diff --git a/coreapi/sal.h b/include/sal/sal.h similarity index 59% rename from coreapi/sal.h rename to include/sal/sal.h index 25d8d20bc..655613661 100644 --- a/coreapi/sal.h +++ b/include/sal/sal.h @@ -26,9 +26,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef sal_h #define sal_h +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "mediastreamer2/mscommon.h" #include "ortp/ortp_srtp.h" +#ifndef LINPHONE_PUBLIC + #define LINPHONE_PUBLIC MS2_PUBLIC +#endif + /*Dirty hack, keep in sync with mediastreamer2/include/mediastream.h */ #ifndef PAYLOAD_TYPE_FLAG_CAN_RECV #define PAYLOAD_TYPE_FLAG_CAN_RECV PAYLOAD_TYPE_USER_FLAG_1 @@ -50,6 +58,8 @@ struct SalCustomHeader; typedef struct SalCustomHeader SalCustomHeader; +struct addrinfo; + typedef enum { SalTransportUDP, /*UDP*/ SalTransportTCP, /*TCP*/ @@ -68,27 +78,35 @@ SalTransport sal_transport_parse(const char*); /* Address manipulation API*/ SalAddress * sal_address_new(const char *uri); SalAddress * sal_address_clone(const SalAddress *addr); +SalAddress * sal_address_ref(SalAddress *addr); +void sal_address_unref(SalAddress *addr); const char *sal_address_get_scheme(const SalAddress *addr); const char *sal_address_get_display_name(const SalAddress* addr); -char *sal_address_get_display_name_unquoted(const SalAddress *addr); +const char *sal_address_get_display_name_unquoted(const SalAddress *addr); const char *sal_address_get_username(const SalAddress *addr); const char *sal_address_get_domain(const SalAddress *addr); -const char * sal_address_get_port(const SalAddress *addr); -int sal_address_get_port_int(const SalAddress *addr); +int sal_address_get_port(const SalAddress *addr); +bool_t sal_address_is_secure(const SalAddress *addr); + SalTransport sal_address_get_transport(const SalAddress* addr); +const char* sal_address_get_transport_name(const SalAddress* addr); void sal_address_set_display_name(SalAddress *addr, const char *display_name); void sal_address_set_username(SalAddress *addr, const char *username); void sal_address_set_domain(SalAddress *addr, const char *host); +#ifdef USE_BELLESIP +void sal_address_set_port(SalAddress *uri, int port); +#else void sal_address_set_port(SalAddress *addr, const char *port); void sal_address_set_port_int(SalAddress *uri, int port); +#endif void sal_address_clean(SalAddress *addr); char *sal_address_as_string(const SalAddress *u); char *sal_address_as_string_uri_only(const SalAddress *u); void sal_address_destroy(SalAddress *u); void sal_address_set_param(SalAddress *u,const char* name,const char* value); void sal_address_set_transport(SalAddress* addr,SalTransport transport); - +void sal_address_set_transport_name(SalAddress* addr,const char* transport); Sal * sal_init(); void sal_uninit(Sal* sal); @@ -101,12 +119,14 @@ typedef enum { SalVideo, SalOther } SalStreamType; +const char* sal_stream_type_to_string(SalStreamType type); typedef enum{ SalProtoUnknown, SalProtoRtpAvp, SalProtoRtpSavp }SalMediaProto; +const char* sal_media_proto_to_string(SalMediaProto type); typedef enum{ SalStreamSendRecv, @@ -114,6 +134,8 @@ typedef enum{ SalStreamRecvOnly, SalStreamInactive }SalStreamDir; +const char* sal_stream_dir_to_string(SalStreamDir type); + #define SAL_ENDPOINT_CANDIDATE_MAX 2 @@ -144,11 +166,13 @@ typedef struct SalIceRemoteCandidate { #define SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN 256 #define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256 +#define SAL_SRTP_KEY_SIZE 41 + typedef struct SalSrtpCryptoAlgo { unsigned int tag; enum ortp_srtp_crypto_suite_t algo; /* 41= 40 max(key_length for all algo) + '\0' */ - char master_key[41]; + char master_key[SAL_SRTP_KEY_SIZE]; } SalSrtpCryptoAlgo; #define SAL_CRYPTO_ALGO_MAX 4 @@ -218,21 +242,32 @@ void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_ typedef struct SalOpBase{ Sal *root; char *route; /*or request-uri for REGISTER*/ + MSList* route_addresses; /*list of SalAddress* */ +#ifndef USE_BELLESIP char *contact; +#else + SalAddress* contact_address; +#endif char *from; + SalAddress* from_address; char *to; + SalAddress* to_address; char *origin; + SalAddress* origin_address; char *remote_ua; SalMediaDescription *local_media; SalMediaDescription *remote_media; void *user_pointer; - char* call_id; + const char* call_id; char *remote_contact; - SalCustomHeader *custom_headers; + SalAddress* service_route; /*as defined by rfc3608, might be a list*/ + SalCustomHeader *sent_custom_headers; + SalCustomHeader *recv_custom_headers; } SalOpBase; typedef enum SalError{ + SalErrorNone, SalErrorNoResponse, SalErrorProtocol, SalErrorFailure, /* see SalReason for more details */ @@ -248,9 +283,15 @@ typedef enum SalReason{ SalReasonDoNotDisturb, SalReasonMedia, SalReasonForbidden, - SalReasonUnknown + SalReasonUnknown, + SalReasonServiceUnavailable, + SalReasonRequestPending, + SalReasonUnauthorized, + SalReasonNotAcceptable }SalReason; +const char* sal_reason_to_string(const SalReason reason); + typedef enum SalPresenceStatus{ SalPresenceOffline, SalPresenceOnline, @@ -262,8 +303,14 @@ typedef enum SalPresenceStatus{ SalPresenceDonotdisturb, SalPresenceMoved, SalPresenceAltService, + SalPresenceOnVacation }SalPresenceStatus; +struct _SalPresenceModel; +typedef struct _SalPresenceModel SalPresenceModel; + +const char* sal_presence_status_to_string(const SalPresenceStatus status); + typedef enum SalReferStatus{ SalReferTrying, SalReferSuccess, @@ -271,6 +318,8 @@ typedef enum SalReferStatus{ }SalReferStatus; typedef enum SalSubscribeStatus{ + SalSubscribeNone, + SalSubscribePending, SalSubscribeActive, SalSubscribeTerminated }SalSubscribeStatus; @@ -281,6 +330,49 @@ typedef enum SalTextDeliveryStatus{ SalTextDeliveryFailed }SalTextDeliveryStatus; +/** + * auth event mode + * */ +typedef enum SalAuthMode { /*this enum must be same as belle_sip_auth_mode_t*/ + SalAuthModeHttpDigest, /** Digest authentication requested*/ + SalAuthModeTls /** Client certificate requested*/ +}SalAuthMode; + +struct _SalCertificatesChain; +typedef struct _SalCertificatesChain SalCertificatesChain; +struct _SalSigningKey; +typedef struct _SalSigningKey SalSigningKey; + +/** + * Format of certificate buffer + * */ +typedef enum SalCertificateRawFormat {/*this enum must be same as belle_sip_certificate_raw_format_t*/ + SAL_CERTIFICATE_RAW_FORMAT_PEM, /** PEM format*/ + SAL_CERTIFICATE_RAW_FORMAT_DER /** ASN.1 raw format*/ +}SalCertificateRawFormat; + + + +typedef struct SalAuthInfo{ + char *username; + char *userid; + char *password; + char *realm; + char *domain; + char *ha1; + SalAuthMode mode; + SalSigningKey *key; + SalCertificatesChain *certificates; +}SalAuthInfo; + +typedef struct SalBody{ + const char *type; + const char *subtype; + const void *data; + size_t size; + const char *encoding; +}SalBody; + typedef void (*SalOnCallReceived)(SalOp *op); typedef void (*SalOnCallRinging)(SalOp *op); typedef void (*SalOnCallAccepted)(SalOp *op); @@ -289,8 +381,9 @@ typedef void (*SalOnCallUpdating)(SalOp *op);/*< Called when a reINVITE is recei typedef void (*SalOnCallTerminated)(SalOp *op, const char *from); typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code); typedef void (*SalOnCallReleased)(SalOp *salop); -typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username); -typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username); +typedef void (*SalOnAuthRequestedLegacy)(SalOp *op, const char *realm, const char *username); +typedef bool_t (*SalOnAuthRequested)(Sal *sal,SalAuthInfo* info); +typedef void (*SalOnAuthFailure)(SalOp *op, SalAuthInfo* info); typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered); typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason, const char *details); typedef void (*SalOnVfuRequest)(SalOp *op); @@ -298,12 +391,23 @@ typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf); typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto); typedef void (*SalOnTextReceived)(SalOp *op, const SalMessage *msg); typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status); -typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *event); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); -typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg); -typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from); -typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from); +typedef void (*SalOnSubscribeResponse)(SalOp *op, SalSubscribeStatus status, SalError error, SalReason reason); +typedef void (*SalOnNotify)(SalOp *op, SalSubscribeStatus status, const char *event, const SalBody *body); +typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *event, const SalBody *body); +typedef void (*SalOnSubscribeClosed)(SalOp *salop); +typedef void (*SalOnParsePresenceRequested)(SalOp *salop, const char *content_type, const char *content_subtype, const char *content, SalPresenceModel **result); +typedef void (*SalOnConvertPresenceToXMLRequested)(SalOp *salop, SalPresenceModel *presence, const char *contact, char **content); +typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceModel *model, const char *msg); +typedef void (*SalOnSubscribePresenceReceived)(SalOp *salop, const char *from); +typedef void (*SalOnSubscribePresenceClosed)(SalOp *salop, const char *from); typedef void (*SalOnPingReply)(SalOp *salop); +typedef void (*SalOnInfoReceived)(SalOp *salop, const SalBody *body); +typedef void (*SalOnPublishResponse)(SalOp *salop, SalError error, SalReason reason); +typedef void (*SalOnExpire)(SalOp *salop); +/*allows sal implementation to access auth info if available, return TRUE if found*/ + + typedef struct SalCallbacks{ SalOnCallReceived call_received; @@ -314,8 +418,7 @@ typedef struct SalCallbacks{ SalOnCallTerminated call_terminated; SalOnCallFailure call_failure; SalOnCallReleased call_released; - SalOnAuthRequested auth_requested; - SalOnAuthSuccess auth_success; + SalOnAuthFailure auth_failure; SalOnRegisterSuccess register_success; SalOnRegisterFailure register_failure; SalOnVfuRequest vfu_request; @@ -323,52 +426,84 @@ typedef struct SalCallbacks{ SalOnRefer refer_received; SalOnTextReceived text_received; SalOnTextDeliveryUpdate text_delivery_update; - SalOnNotify notify; - SalOnNotifyPresence notify_presence; SalOnNotifyRefer notify_refer; SalOnSubscribeReceived subscribe_received; SalOnSubscribeClosed subscribe_closed; + SalOnSubscribeResponse subscribe_response; + SalOnNotify notify; + SalOnSubscribePresenceReceived subscribe_presence_received; + SalOnSubscribePresenceClosed subscribe_presence_closed; + SalOnParsePresenceRequested parse_presence_requested; + SalOnConvertPresenceToXMLRequested convert_presence_to_xml_requested; + SalOnNotifyPresence notify_presence; SalOnPingReply ping_reply; + SalOnAuthRequested auth_requested; + SalOnInfoReceived info_received; + SalOnPublishResponse on_publish_response; + SalOnExpire on_expire; }SalCallbacks; -typedef struct SalAuthInfo{ - char *username; - char *userid; - char *password; - char *realm; -}SalAuthInfo; + SalAuthInfo* sal_auth_info_new(); SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info); -void sal_auth_info_delete(const SalAuthInfo* auth_info); +void sal_auth_info_delete(SalAuthInfo* auth_info); +LINPHONE_PUBLIC int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]); +SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info); +SalSigningKey *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info); +SalCertificatesChain *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info); +void sal_auth_info_set_mode(SalAuthInfo* auth_info, SalAuthMode mode); + +/** Parse a file containing either a certificate chain order in PEM format or a single DER cert + * @param auth_info structure where to store the result of parsing + * @param path path to certificate chain file + * @param format either PEM or DER + */ +void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path, SalCertificateRawFormat format); + +/** + * Parse a file containing either a private or public rsa key + * @param auth_info structure where to store the result of parsing + * @param passwd password (optionnal) + */ +void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd); + +void sal_certificates_chain_delete(SalCertificatesChain *chain); +void sal_signing_key_delete(SalSigningKey *key); + + void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs); int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure); int sal_unlisten_ports(Sal *ctx); +int sal_transport_available(Sal *ctx, SalTransport t); void sal_set_dscp(Sal *ctx, int dscp); int sal_reset_transports(Sal *ctx); ortp_socket_t sal_get_socket(Sal *ctx); void sal_set_user_agent(Sal *ctx, const char *user_agent); +void sal_append_stack_string_to_user_agent(Sal *ctx); /*keepalive period in ms*/ void sal_set_keepalive_period(Sal *ctx,unsigned int value); void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled); +int sal_enable_tunnel(Sal *ctx, void *tunnelclient); +void sal_disable_tunnel(Sal *ctx); /** * returns keepalive period in ms * 0 desactiaved * */ unsigned int sal_get_keepalive_period(Sal *ctx); void sal_use_session_timers(Sal *ctx, int expires); -void sal_use_double_registrations(Sal *ctx, bool_t enabled); -void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled); void sal_use_dates(Sal *ctx, bool_t enabled); -void sal_reuse_authorization(Sal *ctx, bool_t enabled); void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec); void sal_use_rport(Sal *ctx, bool_t use_rports); -void sal_use_101(Sal *ctx, bool_t use_101); +void sal_enable_auto_contacts(Sal *ctx, bool_t enabled); void sal_set_root_ca(Sal* ctx, const char* rootCa); const char *sal_get_root_ca(Sal* ctx); void sal_verify_server_certificates(Sal *ctx, bool_t verify); void sal_verify_server_cn(Sal *ctx, bool_t verify); +void sal_set_uuid(Sal*ctx, const char *uuid); +int sal_create_uuid(Sal*ctx, char *uuid, size_t len); +void sal_enable_test_features(Sal*ctx, bool_t enabled); int sal_iterate(Sal *sal); MSList * sal_get_pending_auths(Sal *sal); @@ -378,28 +513,52 @@ SalOp * sal_op_new(Sal *sal); /*generic SalOp API, working for all operations */ Sal *sal_op_get_sal(const SalOp *op); +#ifndef USE_BELLESIP void sal_op_set_contact(SalOp *op, const char *contact); +#else +#define sal_op_set_contact sal_op_set_contact_address /*for liblinphone compatibility*/ +void sal_op_set_contact_address(SalOp *op, const SalAddress* address); +#endif void sal_op_set_route(SalOp *op, const char *route); +void sal_op_set_route_address(SalOp *op, const SalAddress* address); +void sal_op_add_route_address(SalOp *op, const SalAddress* address); void sal_op_set_from(SalOp *op, const char *from); +void sal_op_set_from_address(SalOp *op, const SalAddress *from); void sal_op_set_to(SalOp *op, const char *to); +void sal_op_set_to_address(SalOp *op, const SalAddress *to); +SalOp *sal_op_ref(SalOp* h); void sal_op_release(SalOp *h); void sal_op_authenticate(SalOp *h, const SalAuthInfo *info); void sal_op_cancel_authentication(SalOp *h); void sal_op_set_user_pointer(SalOp *h, void *up); -int sal_op_get_auth_requested(SalOp *h, const char **realm, const char **username); +SalAuthInfo * sal_op_get_auth_requested(SalOp *h); const char *sal_op_get_from(const SalOp *op); +const SalAddress *sal_op_get_from_address(const SalOp *op); const char *sal_op_get_to(const SalOp *op); +const SalAddress *sal_op_get_to_address(const SalOp *op); +#ifndef USE_BELLESIP const char *sal_op_get_contact(const SalOp *op); +#else +const SalAddress *sal_op_get_contact_address(const SalOp *op); +#define sal_op_get_contact sal_op_get_contact_address /*for liblinphone compatibility*/ +#endif const char *sal_op_get_route(const SalOp *op); +const MSList* sal_op_get_route_addresses(const SalOp *op); const char *sal_op_get_proxy(const SalOp *op); const char *sal_op_get_remote_contact(const SalOp *op); /*for incoming requests, returns the origin of the packet as a sip uri*/ const char *sal_op_get_network_origin(const SalOp *op); +const SalAddress *sal_op_get_network_origin_address(const SalOp *op); /*returns far-end "User-Agent" string */ const char *sal_op_get_remote_ua(const SalOp *op); void *sal_op_get_user_pointer(const SalOp *op); const char* sal_op_get_call_id(const SalOp *op); +const SalAddress* sal_op_get_service_route(const SalOp *op); +void sal_op_set_service_route(SalOp *op,const SalAddress* service_route); + +void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled); + /*Call API*/ int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc); int sal_call(SalOp *h, const char *from, const char *to); @@ -426,6 +585,7 @@ int sal_call_notify_refer_state(SalOp *h, SalOp *newcall); /*Registration*/ int sal_register(SalOp *op, const char *proxy, const char *from, int expires); +/*refresh a register, -1 mean use the last known value*/ int sal_register_refresh(SalOp *op, int expires); int sal_unregister(SalOp *h); @@ -434,20 +594,45 @@ int sal_text_send(SalOp *op, const char *from, const char *to, const char *text) int sal_message_send(SalOp *op, const char *from, const char *to, const char* content_type, const char *msg); /*presence Subscribe/notify*/ -int sal_subscribe_presence(SalOp *op, const char *from, const char *to); -int sal_unsubscribe(SalOp *op); -int sal_subscribe_accept(SalOp *op); -int sal_subscribe_decline(SalOp *op); -int sal_notify_presence(SalOp *op, SalPresenceStatus status, const char *status_message); -int sal_notify_close(SalOp *op); +int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expires); +int sal_notify_presence(SalOp *op, SalPresenceModel *presence); +int sal_notify_presence_close(SalOp *op); /*presence publish */ -int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus status); +int sal_publish_presence(SalOp *op, const char *from, const char *to, int expires, SalPresenceModel *presence); /*ping: main purpose is to obtain its own contact address behind firewalls*/ int sal_ping(SalOp *op, const char *from, const char *to); +/*info messages*/ +int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body); + +/*generic subscribe/notify/publish api*/ +int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body); +int sal_unsubscribe(SalOp *op); +int sal_subscribe_accept(SalOp *op); +int sal_subscribe_decline(SalOp *op, SalReason reason); +int sal_notify(SalOp *op, const SalBody *body); +int sal_notify_close(SalOp *op); +int sal_publish(SalOp *op, const char *from, const char *to, const char*event_name, int expires, const SalBody *body); + +/*privacy, must be in sync with LinphonePrivacyMask*/ +typedef enum _SalPrivacy { + SalPrivacyNone=0x0, + SalPrivacyUser=0x1, + SalPrivacyHeader=0x2, + SalPrivacySession=0x4, + SalPrivacyId=0x8, + SalPrivacyCritical=0x10, + SalPrivacyDefault=0x8000 +} SalPrivacy; +typedef unsigned int SalPrivacyMask; + +const char* sal_privacy_to_string(SalPrivacy privacy); +void sal_op_set_privacy(SalOp* op,SalPrivacy privacy); +SalPrivacy sal_op_get_privacy(const SalOp* op); + #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); @@ -456,24 +641,58 @@ int sal_ping(SalOp *op, const char *from, const char *to); /*misc*/ void sal_get_default_local_ip(Sal *sal, int address_family, char *ip, size_t iplen); -struct SalCustomHeader{ - MSList node; - char *header_name; - char *header_value; -}; +typedef void (*SalResolverCallback)(void *data, const char *name, struct addrinfo *ai_list); + +typedef struct SalResolverContext SalResolverContext; + +SalResolverContext * sal_resolve_a(Sal* sal, const char *name, int port, int family, SalResolverCallback cb, void *data); +//void sal_resolve_cancel(Sal *sal, SalResolverContext *ctx); SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value); const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name); void sal_custom_header_free(SalCustomHeader *ch); SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch); -const SalCustomHeader *sal_op_get_custom_header(SalOp *op); -void sal_op_set_custom_header(SalOp *op, SalCustomHeader* ch); +const SalCustomHeader *sal_op_get_recv_custom_header(SalOp *op); + +void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch); + +void sal_enable_logs(); +void sal_disable_logs(); /*internal API */ void __sal_op_init(SalOp *b, Sal *sal); void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/); +void __sal_op_set_network_origin_address(SalOp *op, SalAddress *origin); void __sal_op_set_remote_contact(SalOp *op, const char *ct); void __sal_op_free(SalOp *b); +/*test api*/ +/*0 for no error*/ +LINPHONE_PUBLIC void sal_set_send_error(Sal *sal,int value); +/*1 for no error*/ +LINPHONE_PUBLIC void sal_set_recv_error(Sal *sal,int value); + +/*always answer 480 if value=true*/ +LINPHONE_PUBLIC void sal_enable_unconditional_answer(Sal *sal,int value); + +/*refresher retry after value in ms*/ +LINPHONE_PUBLIC void sal_set_refresher_retry_after(Sal *sal,int value); +LINPHONE_PUBLIC int sal_get_refresher_retry_after(const Sal *sal); +/*enable contact fixing*/ +void sal_nat_helper_enable(Sal *sal,bool_t enable); +bool_t sal_nat_helper_enabled(Sal *sal); + +LINPHONE_PUBLIC void sal_set_dns_timeout(Sal* sal,int timeout); +LINPHONE_PUBLIC int sal_get_dns_timeout(const Sal* sal); +LINPHONE_PUBLIC void sal_enable_dns_srv(Sal *sal, bool_t enable); +LINPHONE_PUBLIC bool_t sal_dns_srv_enabled(const Sal *sal); +LINPHONE_PUBLIC void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_file); +LINPHONE_PUBLIC const char *sal_get_dns_user_hosts_file(const Sal *sal); +unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size); + +int sal_body_has_type(const SalBody *body, const char *type, const char *subtype); +/*this function parses a document with key=value pairs separated by new lines, and extracts the value for a given key*/ +int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size); + #endif diff --git a/java/.DS_Store b/java/.DS_Store deleted file mode 100644 index e6dc460bb..000000000 Binary files a/java/.DS_Store and /dev/null differ diff --git a/java/common/org/linphone/core/LinphoneAuthInfo.java b/java/common/org/linphone/core/LinphoneAuthInfo.java index 0213720eb..5e2744a1e 100644 --- a/java/common/org/linphone/core/LinphoneAuthInfo.java +++ b/java/common/org/linphone/core/LinphoneAuthInfo.java @@ -83,6 +83,23 @@ public interface LinphoneAuthInfo { */ void setHa1(String ha1); + /** + * Sets the domain + * @param domain + */ + void setDomain(String domain); + + /** + * Gets the domain + * @return the domain + */ + String getDomain(); + + /** + * Clones a current auth info + * @return the clone auth info + */ + LinphoneAuthInfo clone(); } diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index 893572e2e..62be0d638 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -292,4 +292,27 @@ public interface LinphoneCall { * Stop call recording. */ void stopRecording(); + + /** + * If a call transfer has been initiated for this call, returns the call state of the new call performed at the remote end as a result of the transfer request. + * @return the call state of the new call performed by the referee to the refer target. + */ + State getTransferState(); + + /** + * Send an info message to remote peer. + */ + void sendInfoMessage(LinphoneInfoMessage msg); + + /** + * Returns the transferer if this call was started automatically as a result of an incoming transfer request. + * The call in which the transfer request was received is returned in this case. + **/ + LinphoneCall getTransfererCall(); + + /** + * When this call has received a transfer request, returns the new call that was automatically created as a result of the transfer. + **/ + LinphoneCall getTransferTargetCall(); + } diff --git a/java/common/org/linphone/core/LinphoneCallParams.java b/java/common/org/linphone/core/LinphoneCallParams.java index b6d5ef33d..530cf63b9 100644 --- a/java/common/org/linphone/core/LinphoneCallParams.java +++ b/java/common/org/linphone/core/LinphoneCallParams.java @@ -93,4 +93,16 @@ public interface LinphoneCallParams { * @return value for the header, or null if it doesn't exist. */ String getCustomHeader(String name); + + /** + * Set the privacy for the call. + * @param privacy_mask a or'd int of values defined in interface {@link org.linphone.core.Privacy} + */ + void setPrivacy(int privacy_mask); + + /** + * Get the privacy mask requested for this call. + * @return the privacy mask as defined in interface {@link org.linphone.core.Privacy} + */ + int getPrivacy(); } diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index b6b6c30ec..8345df382 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -112,4 +112,33 @@ public interface LinphoneChatMessage { * @return the time in milliseconds */ long getTime(); + + /** + * Gets the status of the message + * @return the status of the message + */ + LinphoneChatMessage.State getStatus(); + + /** + * Returns wether or not the message has been read + * @return true if it has been read, flase otherwise + */ + boolean isRead(); + + /** + * Returns wether the message has been sent or received + * @return true if the message has been sent, false if it has been received + */ + boolean isOutgoing(); + + /** + * THIS METHOD IS ONLY USED TO IMPORT OLD MESSAGES, DON'T USE IT FOR ANY OTHER USAGE! + */ + void store(); + + /** + * Returns the id used to id this message in the database + * @return the id used to id this message in the database + */ + int getStorageId(); } diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index d6512f170..5c87f5647 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -17,6 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; + +import org.linphone.core.LinphoneChatMessage.State; + /** * * A chat room is the place where text messages are exchanged. @@ -48,4 +51,56 @@ public interface LinphoneChatRoom { * @return LinphoneChatMessage object */ LinphoneChatMessage createLinphoneChatMessage(String message); + + /** + * Returns the chat history associated with the peer address associated with this chat room + * @return an array of LinphoneChatMessage + */ + LinphoneChatMessage[] getHistory(); + + /** + * Returns the chat history associated with the peer address associated with this chat room + * @param limit the maximum number of messages to fetch + * @return an array of LinphoneChatMessage + */ + LinphoneChatMessage[] getHistory(int limit); + + /** + * Destroys a LinphoneChatRoom. + */ + void destroy(); + + /** + * Returns the amount of unread messages associated with the peer of this chatRoom. + * @return the amount of unread messages + */ + int getUnreadMessagesCount(); + + /** + * Deletes all the messages associated with the peer of this chat room + */ + void deleteHistory(); + + /** + * Marks all the messages in this conversation as read + */ + void markAsRead(); + + /** + * Deletes a message + * @param message the message to delete + */ + void deleteMessage(LinphoneChatMessage message); + + /** + * Update the value stored in the database for the external_body_url field + * @param message to update + */ + void updateUrl(LinphoneChatMessage message); + + /** + * Create a LinphoneChatMessage + * @return LinphoneChatMessage object + */ + LinphoneChatMessage createLinphoneChatMessage(String message, String url, State state, long timestamp, boolean isRead, boolean isIncoming); } diff --git a/java/common/org/linphone/core/LinphoneContent.java b/java/common/org/linphone/core/LinphoneContent.java new file mode 100644 index 000000000..10c6e3dc9 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneContent.java @@ -0,0 +1,62 @@ +package org.linphone.core; + +/** + * LinphoneContent interface describes a SIP message content (body). + * It can be used together with the LinphoneInfoMessage, in order to add content attachment to the INFO message. + * @author smorlat + * + */ +public interface LinphoneContent { + /** + * Get the type of the content, for example "application" + * @return the type + */ + String getType(); + /** + * Get the subtype of the content, for example "html" + * @return the subtype + */ + String getSubtype(); + /** + * Get the encoding applied to the data, can be null if no encoding. + **/ + String getEncoding(); + /** + * Get the data as a string. + * @return the data + */ + String getDataAsString(); + /** + * Get the data as a byte array. + **/ + byte [] getData(); + /** + * Get the data size. + * @return the data size. + */ + int getSize(); + + /** + * Set the content type, for example "application" + * @param type the content's primary type + */ + void setType(String type); + /** + * Set the subtype, for example "text" + * @param subtype the subtype + */ + void setSubtype(String subtype); + /** + * Set the encoding applied to the data, can be null if no encoding. + **/ + void setEncoding(String encoding); + /** + * Set the data, supplied as String. + * @param data the data + */ + void setStringData(String data); + /** + * Set the data, as a byte buffer. + **/ + void setData(byte data[]); +} diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index d76acad9a..ef310bc9a 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -20,9 +20,11 @@ package org.linphone.core; import java.util.Vector; -import org.linphone.core.LinphoneCall.State; +import org.linphone.mediastream.video.AndroidVideoWindowImpl; import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration; +import android.view.SurfaceView; + /** * Linphone core main object created by method {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)}. * @@ -327,6 +329,11 @@ public interface LinphoneCore { * Ko */ static public UpnpState Ko = new UpnpState(6, "Ko"); + /** + * Blacklisted + */ + static public UpnpState Blacklisted = new UpnpState(7, "Blacklisted"); + protected final int mValue; private final String mStringValue; @@ -362,6 +369,13 @@ public interface LinphoneCore { * @throws LinphoneCoreException */ public void addProxyConfig(LinphoneProxyConfig proxyCfg) throws LinphoneCoreException; + + /** + * Removes a proxy configuration. + * @param proxyCfg + */ + public void removeProxyConfig(LinphoneProxyConfig proxyCfg); + /** * Sets the default proxy. *
@@ -377,6 +391,21 @@ public interface LinphoneCore { */ public LinphoneProxyConfig getDefaultProxyConfig() ; + /** + * Returns an array with all the auth infos stored in LinphoneCore + */ + LinphoneAuthInfo[] getAuthInfosList(); + + /** + * Returns a matching auth info or null if no match found + */ + LinphoneAuthInfo findAuthInfo(String username, String realm, String domain); + /** + * Removes a auth info. + * @param authInfo + */ + public void removeAuthInfo(LinphoneAuthInfo authInfo); + /** * clear all the added auth info */ @@ -613,6 +642,12 @@ public interface LinphoneCore { * */ void enablePayloadType(PayloadType pt, boolean enable) throws LinphoneCoreException; + + /** + * Returns whether or not the payload is enabled in linphonecore. + */ + boolean isPayloadTypeEnabled(PayloadType pt); + /** * Enables or disable echo cancellation. * @param enable @@ -669,18 +704,36 @@ public interface LinphoneCore { void addFriend(LinphoneFriend lf) throws LinphoneCoreException; /** - * Set my presence status - * @param minute_away how long in away - * @param status sip uri used to redirect call in state LinphoneStatusMoved + * @brief Set my presence status + * @param minutes_away how long in away + * @param alternative_contact sip uri used to redirect call in state LinphoneStatusMoved + * @param status OnlineStatus + * @deprecated Use setPresenceModel() instead */ - void setPresenceInfo(int minute_away,String alternative_contact, OnlineStatus status); + void setPresenceInfo(int minutes_away, String alternative_contact, OnlineStatus status); + /** + * @brief Get my presence status + * @return OnlineStatus + * @deprecated Use getPresenceModel() instead + */ + OnlineStatus getPresenceInfo(); + /** + * @brief Set my presence status + * @param presence #LinphonePresenceModel + */ + void setPresenceModel(PresenceModel presence); + /** + * @brief Get my presence status + * @return A #PresenceModel object, or null if no presence model has been set. + */ + PresenceModel getPresenceModel(); /** * Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org * @param to destination address for messages * * @return {@link LinphoneChatRoom} where messaging can take place. */ - LinphoneChatRoom createChatRoom(String to); + LinphoneChatRoom getOrCreateChatRoom(String to); /** * Set the native video window id where the video is to be displayed. * On Android, it must be of type {@link AndroidVideoWindowImpl} @@ -713,6 +766,13 @@ public interface LinphoneCore { **/ int getVideoDevice(); + + /** + * Teturns true if the underlying sdk support video + * + * */ + boolean isVideoSupported(); + /** * Enables video globally. * @@ -838,6 +898,14 @@ public interface LinphoneCore { * **/ void setPreferredVideoSize(VideoSize vSize); + /** + * Sets the preferred video size giving a known size name. + * + * This applies only to the stream that is captured and sent to the remote party, + * since we accept all standard video size on the receive path. + * @param name A known video name (eg. vga or 720p) + **/ + void setPreferredVideoSizeByName(String name); /** * get current preferred video size for sending. * @return video size @@ -879,6 +947,9 @@ public interface LinphoneCore { boolean needsEchoCalibration(); void enableIpv6(boolean enable); + + boolean isIpv6Enabled(); + /** * @deprecated * @param i @@ -1101,6 +1172,17 @@ public interface LinphoneCore { * @param autoAccept video shall be accepter by default for incoming calls **/ void setVideoPolicy(boolean autoInitiate, boolean autoAccept); + + /** + * Gets the policy for the autoInitiate video + */ + boolean getVideoAutoInitiatePolicy(); + + /** + * Gets the policy for the autoAccept video + */ + boolean getVideoAutoAcceptPolicy(); + /** Set static picture to be used when "Static picture" is the video device * @param path to the static picture file * */ @@ -1219,15 +1301,35 @@ public interface LinphoneCore { */ void setPrimaryContact(String displayName, String username); + /** + * Returns the username used if no LinphoneProxyConfig configured + */ + String getPrimaryContactUsername(); + + /** + * Returns the display name used if no LinphoneProxyConfig configured + */ + String getPrimaryContactDisplayName(); + /** * Enable/Disable the use of SIP INFO for DTMFs */ void setUseSipInfoForDtmfs(boolean use); + /** + * Returns the state of use of SIP INFO for DTMFs + */ + boolean getUseSipInfoForDtmfs(); + /** * Enable/Disable the use of inband DTMFs */ void setUseRfc2833ForDtmfs(boolean use); + + /** + * Returns the state of use of inband DTMFs + */ + boolean getUseRfc2833ForDtmfs(); /** * @return returns LpConfig object to read/write to the config file: usefull if you wish to extend @@ -1259,5 +1361,46 @@ public interface LinphoneCore { * the external ip address is not available return null. */ public String getUpnpExternalIpaddress(); - + + /** + * Create an empty INFO message. + * It can later be sent using {@link LinphoneCall.sendInfoMessage() }. + * @return the new info message. + */ + public LinphoneInfoMessage createInfoMessage(); + + /** + * Sends an outgoing subscription for a resource with given event, expiration period, and content. + * The state changes of the new subscriptions can be followed thanks to { @link LinphoneCoreListener.subscriptionStateChanged() } and + * { @link LinphoneCoreListener.notifyReceived }. + * @param resource the address of the resource for which the event needs to be monitored. + * @param event the event name, as specified in the event package RFC. + * @param expires the expiration period in seconds. + * @param content optional content of the subscription. + * @return a LinphoneEvent representing the subscription context. + */ + public LinphoneEvent subscribe(LinphoneAddress resource, String event, int expires, LinphoneContent content ); + + /** + * Publish an event. + * After the initial publication, updates can be done with { @link LinphoneEvent.updatePublish() } + * @param resource the resource to which the event belongs. + * @param event the event name as specified in the event package RFC. + * @param expires valid time for the event. + * @param content content of the publish. + * @return a LinphoneEvent representing the publish context. + */ + public LinphoneEvent publish(LinphoneAddress resource, String event, int expires, LinphoneContent content); + + /** + * Sets the path to the database where the chat messages will be stored (if enabled) + * @param path the database where the chat messages will be stored. + */ + public void setChatDatabasePath(String path); + + /** + * Gets the chat rooms + * @return an array of LinphoneChatRoom + */ + public LinphoneChatRoom[] getChatRooms(); } diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 5e8637999..95cfdeaf0 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -54,7 +54,7 @@ abstract public class LinphoneCoreFactory { * @param userid user id as set in auth header * @param passwd * */ - abstract public LinphoneAuthInfo createAuthInfo(String username,String password, String realm); + abstract public LinphoneAuthInfo createAuthInfo(String username,String password, String realm, String domain); /** * create {@link LinphoneAuthInfo} * @param username @@ -63,7 +63,7 @@ abstract public class LinphoneCoreFactory { * @param ha1 * @param realm * */ - abstract public LinphoneAuthInfo createAuthInfo(String username, String userid, String passwd, String ha1,String realm); + abstract public LinphoneAuthInfo createAuthInfo(String username, String userid, String passwd, String ha1, String realm, String domain); abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata) throws LinphoneCoreException; abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener) throws LinphoneCoreException; @@ -81,8 +81,9 @@ abstract public class LinphoneCoreFactory { * Constructs a LinphoneAddress object by parsing the user supplied address, given as a string. * @param address should be like sip:joe@sip.linphone.org * @return + * @throws LinphoneCoreException if address cannot be parsed */ - abstract public LinphoneAddress createLinphoneAddress(String address); + abstract public LinphoneAddress createLinphoneAddress(String address) throws LinphoneCoreException; abstract public LpConfig createLpConfig(String file); abstract public LinphoneProxyConfig createProxyConfig(String identity, String proxy,String route,boolean enableRegister) throws LinphoneCoreException; @@ -106,5 +107,34 @@ abstract public class LinphoneCoreFactory { */ abstract public LinphoneFriend createLinphoneFriend(); + /** + * Create a LinphoneContent object from string data. + */ + abstract public LinphoneContent createLinphoneContent(String type, String subType, String data); + + /** + * Create a LinphoneContent object from byte array. + */ + abstract public LinphoneContent createLinphoneContent(String type, String subType,byte [] data, String encoding); + /** + * Create a PresenceActivity object. + */ + abstract public PresenceActivity createPresenceActivity(PresenceActivityType type, String description); + + /** + * Create a PresenceService object. + * @param id The id of the presence service. Can be null to generate it automatically. + * @param status The PresenceBasicStatus to set for the PresenceService object. + * @param contact The contact to set for the PresenceService object. Can be null. + * @return A new PresenceService object. + */ + abstract public PresenceService createPresenceService(String id, PresenceBasicStatus status, String contact); + + /** + * Create a PresenceModel object. + */ + abstract public PresenceModel createPresenceModel(); + abstract public PresenceModel createPresenceModel(PresenceActivityType type, String description); + abstract public PresenceModel createPresenceModel(PresenceActivityType type, String description, String note, String lang); } diff --git a/java/common/org/linphone/core/LinphoneCoreListener.java b/java/common/org/linphone/core/LinphoneCoreListener.java index 740bdc29c..60e9e3d59 100644 --- a/java/common/org/linphone/core/LinphoneCoreListener.java +++ b/java/common/org/linphone/core/LinphoneCoreListener.java @@ -117,6 +117,44 @@ public interface LinphoneCoreListener { */ void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event); + /** + * Notifies progress of a call transfer. + * @param lc the LinphoneCore + * @param call the call through which the transfer was sent. + * @param new_call_state the state of the call resulting of the transfer, at the other party. + **/ + void transferState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State new_call_state); + + /** + * Notifies an incoming INFO message. + * @param lc the LinphoneCore. + * @param info the info message + */ + void infoReceived(LinphoneCore lc, LinphoneCall call, LinphoneInfoMessage info); + + /** + * Notifies of subscription requests state changes, including new incoming subscriptions. + * @param lc the LinphoneCore + * @param ev LinphoneEvent object representing the subscription context. + * @param state actual state of the subscription. + */ + void subscriptionStateChanged(LinphoneCore lc, LinphoneEvent ev, SubscriptionState state); + + /** + * Notifies of an incoming NOTIFY received. + * @param lc the linphoneCore + * @param ev a LinphoneEvent representing the subscription context for which this notify belongs, or null if it is a NOTIFY out of of any subscription. + * @param eventName the event name + * @param content content of the NOTIFY request. + */ + void notifyReceived(LinphoneCore lc, LinphoneEvent ev, String eventName, LinphoneContent content); + /** + * Notifies about outgoing generic publish states. + * @param lc the LinphoneCore + * @param ev a LinphoneEvent representing the publish, typically created by {@link LinphoneCore#publish} + * @param state the publish state + */ + void publishStateChanged(LinphoneCore lc, LinphoneEvent ev, PublishState state); /**< @Deprecated Notifies the application that it should show up * @return */ diff --git a/java/common/org/linphone/core/LinphoneEvent.java b/java/common/org/linphone/core/LinphoneEvent.java new file mode 100644 index 000000000..865200dfd --- /dev/null +++ b/java/common/org/linphone/core/LinphoneEvent.java @@ -0,0 +1,71 @@ +package org.linphone.core; + +public interface LinphoneEvent { + /** + * Get the event name as standardized by the event package RFC. + * @return the event name. + */ + String getEventName(); + + /** + * Return subscription direction (incoming or outgoing). For publish initiated LinphoneEvent it is set to Invalid. + * @return the subscription direction. + */ + SubscriptionDir getSubscriptionDir(); + + /** + * Get subscription state. + * @return the current subscription state. + */ + SubscriptionState getSubscriptionState(); + /** + * Accept an incoming subscription. After it is accepted the application can immediately start to send notifications with + * {@link LinphoneEvent.notify() }. + */ + void acceptSubscription(); + + /** + * Reject an incoming subscription. + * @param reason reason code for rejection. + */ + void denySubscription(Reason reason); + + /** + * Sends a NOTIFY request in the context of a LinphoneEvent created by an incoming subscription. + * @param content the data to be put in the notification. + */ + void notify(LinphoneContent content); + + /** + * Update a subscription initiated previously with {@link LinphoneCore.subscribe() } + * @param content the data to be put in the subscribe request. + */ + void updateSubscribe(LinphoneContent content); + + /** + * Update a Publish previously started with {@link LinphoneCore.publish() }. + * @param content the data to be put in the publish request. + */ + void updatePublish(LinphoneContent content); + + /** + * Terminate an outgoing or incoming subscription, depending on the way the LinphoneEvent was created. + */ + void terminate(); + /** + * In the event where an error would be returned or notified relatively to this LinphoneEvent, returns a reason error code. + * @return + */ + Reason getReason(); + + /** + * Assign an application context to the LinphoneEvent, for later use. + * @param obj + */ + void setUserContext(Object obj); + /** + * Retrieve application context previously set by setUserContext(). + * @return + */ + Object getUserContext(); +} diff --git a/java/common/org/linphone/core/LinphoneFriend.java b/java/common/org/linphone/core/LinphoneFriend.java index 417c582d9..1a84498ce 100644 --- a/java/common/org/linphone/core/LinphoneFriend.java +++ b/java/common/org/linphone/core/LinphoneFriend.java @@ -103,10 +103,16 @@ public interface LinphoneFriend { */ boolean isSubscribesEnabled(); /** - * get friend status - * @return + * @brief Get the status of a friend + * @return OnlineStatus + * @deprecated Use getPresenceModel() instead */ OnlineStatus getStatus(); + /** + * @brief Get the presence information of a friend + * @return A #PresenceModel object, or null if the friend do not have presence information (in which case he is considered offline) + */ + PresenceModel getPresenceModel(); /** * Starts editing a friend configuration. *
Because friend configuration must be consistent, applications MUST call {@link #edit()} before doing any attempts to modify friend configuration (such as address or subscription policy and so on). diff --git a/java/common/org/linphone/core/LinphoneInfoMessage.java b/java/common/org/linphone/core/LinphoneInfoMessage.java new file mode 100644 index 000000000..00362e987 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneInfoMessage.java @@ -0,0 +1,32 @@ +package org.linphone.core; + +/** + * The LinphoneInfoMessage represents an informational message (INFO) to be transmitted or received by the LinphoneCore. + * It can be created with {@link LinphoneCore.createInfoMessage() }. + * @author smorlat + * + */ +public interface LinphoneInfoMessage { + /** + * Assign a content to the info message. This is optional. + * @param content + */ + void setContent(LinphoneContent content); + /** + * Get the actual content of the info message. It may be null. + * @return a LinphoneContent object or null + */ + LinphoneContent getContent(); + /** + * Add a specific header to the info message + * @param name the header's name + * @param value the header's value + */ + void addHeader(String name, String value); + /** + * Retrieve a header's value based on its name. + * @param name the header's name + * @return the header's value + */ + String getHeader(String name); +} diff --git a/java/common/org/linphone/core/LinphoneLogHandler.java b/java/common/org/linphone/core/LinphoneLogHandler.java index 9465dccc7..ee88ee5f8 100644 --- a/java/common/org/linphone/core/LinphoneLogHandler.java +++ b/java/common/org/linphone/core/LinphoneLogHandler.java @@ -24,10 +24,10 @@ package org.linphone.core; */ public interface LinphoneLogHandler { public static final int Fatal=1<<4; - public static final int Error=1<<3|Fatal; - public static final int Warn=1<<2|Error; - public static final int Info=1<<1|Warn; - public static final int Debug=1|Info; + public static final int Error=1<<3; + public static final int Warn=1<<2; + public static final int Info=1<<1; + public static final int Debug=1; /** * Method invoked for each traces diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index b6b8919fb..8a5da47a8 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -84,6 +84,12 @@ public interface LinphoneProxyConfig { * @param prefix */ public void setDialPrefix(String prefix); + + /** + * Returns the automatically added international prefix to e164 phone numbers + */ + public String getDialPrefix(); + /** * * Sets whether liblinphone should replace "+" by "00" in dialed numbers (passed to * {@link LinphoneCore#invite(String)}). @@ -91,6 +97,12 @@ public interface LinphoneProxyConfig { */ public void setDialEscapePlus(boolean value); + /** + * Whether liblinphone should replace "+" by "00" in dialed numbers (passed to + * {@link LinphoneCore#invite(String)}). + */ + public boolean getDialEscapePlus(); + /** * get domain host name or ip * @return may be null @@ -134,6 +146,25 @@ public interface LinphoneProxyConfig { */ void setExpires(int delay); + /** + * Gets the registration expiration time. + * @return delay expiration time in seconds. + */ + int getExpires(); + + /** + * Set the privacy for all calls or chat sessions using the identity exposed by this LinphoneProxyConfig + * @param privacy_mask a or'd int of values defined in interface {@link org.linphone.core.Privacy} + */ + void setPrivacy(int privacy_mask); + + /** + * Get the privacy mask requested for this proxy config. + * @return the privacy mask as defined in interface {@link org.linphone.core.Privacy} + */ + int getPrivacy(); + + /** * Sets parameters for the contact * @param parameters to add @@ -151,4 +182,10 @@ public interface LinphoneProxyConfig { * @param e164 phone number */ public int lookupCCCFromE164(String e164); + + /** + * Return reason error code. + * @return reason code. + */ + public Reason getError(); } diff --git a/java/common/org/linphone/core/LpConfig.java b/java/common/org/linphone/core/LpConfig.java index 5be54f6c0..f2503c06b 100644 --- a/java/common/org/linphone/core/LpConfig.java +++ b/java/common/org/linphone/core/LpConfig.java @@ -42,9 +42,89 @@ public interface LpConfig { /** * Sets an integer config item - * @param key + * @param section the section in the lpconfig + * @param key the name of the setting + * @param value the value of the setting */ void setInt(String section, String key, int value); + + /** + * Sets an float config item + * @param section the section in the lpconfig + * @param key the name of the setting + * @param value the value of the setting + */ + void setFloat(String section, String key, float value); + + /** + * Sets an boolean config item + * @param section the section in the lpconfig + * @param key the name of the setting + * @param value the value of the setting + */ + void setBool(String section, String key, boolean value); + + /** + * Sets an string config item + * @param section the section in the lpconfig + * @param key the name of the setting + * @param value the value of the setting + */ + void setString(String section, String key, String value); + + /** + * Sets an integer range config item + * @param section the section in the lpconfig + * @param key the name of the setting + * @param min the min of the range + * @param max the max of the range + */ + void setIntRange(String section, String key, int min, int max); + + /** + * Gets a int from the config + * @param section the section in the lpconfig + * @param key the name of the setting + * @param defaultValue the default value if not set + * @return the value of the setting or the default value if not set + */ + int getInt(String section, String key, int defaultValue); + + /** + * Gets a float from the config + * @param section the section in the lpconfig + * @param key the name of the setting + * @param defaultValue the default value if not set + * @return the value of the setting or the default value if not set + */ + float getFloat(String section, String key, float defaultValue); + + /** + * Gets a boolean from the config + * @param section the section in the lpconfig + * @param key the name of the setting + * @param defaultValue the default value if not set + * @return the value of the setting or the default value if not set + */ + boolean getBool(String section, String key, boolean defaultValue); + + /** + * Gets a string from the config + * @param section the section in the lpconfig + * @param key the name of the setting + * @param defaultValue the default value if not set + * @return the value of the setting or the default value if not set + */ + String getString(String section, String key, String defaultValue); + + /** + * Gets a int range from the config + * @param section the section in the lpconfig + * @param key the name of the setting + * @param defaultValue the default value if not set + * @return the value of the setting or the default value if not set + */ + int[] getIntRange(String section, String key, int defaultMin, int defaultMax); /** * Synchronize LpConfig with file diff --git a/java/common/org/linphone/core/OnlineStatus.java b/java/common/org/linphone/core/OnlineStatus.java index 081084171..9a101d223 100644 --- a/java/common/org/linphone/core/OnlineStatus.java +++ b/java/common/org/linphone/core/OnlineStatus.java @@ -23,7 +23,7 @@ import java.util.Vector; /** * Enum describing remote friend status - * + * @deprecated Use #PresenceModel and #PresenceActivity instead */ public class OnlineStatus { diff --git a/java/common/org/linphone/core/PayloadType.java b/java/common/org/linphone/core/PayloadType.java index 648d77465..3952024c5 100644 --- a/java/common/org/linphone/core/PayloadType.java +++ b/java/common/org/linphone/core/PayloadType.java @@ -19,8 +19,39 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. package org.linphone.core; public interface PayloadType { - + /** + * Obtain the registered mime-type (actually submime) of the PayloadType. For example: "H264", "speex"... + * @return the (sub) mime type. + */ String getMime(); + /** + * Return the RTP clockrate. It is usually the same as the audio sampling rate, and 90000 for video payload types. + * @return + */ int getRate(); + + /** + * Set format parameter string wished for incoming stream. It is advertised in SDP. + * @param fmtp the fmtp string, like "octet-align=1;mode-set=4,5,6,7" + */ + void setRecvFmtp(String fmtp); + + /** + * Return the format parameters wished for incoming stream. + * @return the format parameter string. + */ + String getRecvFmtp(); + + /** + * Set the format parameter effective for the outgoing stream (unusual). + * @param fmtp + */ + void setSendFmtp(String fmtp); + + /** + * Return the format parameter effective for the outgoing stream. + * @return + */ + String getSendFmtp(); } diff --git a/java/common/org/linphone/core/PresenceActivity.java b/java/common/org/linphone/core/PresenceActivity.java new file mode 100644 index 000000000..b965b526b --- /dev/null +++ b/java/common/org/linphone/core/PresenceActivity.java @@ -0,0 +1,61 @@ +/* +PresenceActivity.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public interface PresenceActivity { + + /** + * @brief Gets the string representation of a presence activity. + * @return A String representing the given activity. + */ + String toString(); + + /** + * @brief Gets the activity type of a presence activity. + * @return The #PresenceActivityType of the activity. + */ + PresenceActivityType getType(); + + /** + * @brief Sets the type of activity of a presence activity. + * @param[in] acttype The activity type to set for the activity. + * @return 0 if successful, a value < 0 in case of error. + */ + int setType(PresenceActivityType type); + + /** + * @brief Gets the description of a presence activity. + * @return A String containing the description of the presence activity, or null if no description is specified. + */ + String getDescription(); + + /** + * @brief Sets the description of a presence activity. + * @param[in] description An additional description of the activity. Can be null if no additional description is to be added. + * @return 0 if successful, a value < 0 in case of error. + */ + int setDescription(String description); + + /** + * @brief Gets the native pointer for this object. + */ + long getNativePtr(); + +} diff --git a/java/common/org/linphone/core/PresenceActivityType.java b/java/common/org/linphone/core/PresenceActivityType.java new file mode 100644 index 000000000..c20398661 --- /dev/null +++ b/java/common/org/linphone/core/PresenceActivityType.java @@ -0,0 +1,137 @@ +/* +PresenceActivityType.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +/** Activities as defined in section 3.2 of RFC 4480 */ +public enum PresenceActivityType { + /** This value is not defined in the RFC, it corresponds to no activity with a basic status of "closed". */ + Offline(0), + /** This value is not defined in the RFC, it corresponds to no activity with a basic status of "open". */ + Online(1), + /** The person has a calendar appointment, without specifying exactly of what type. This activity is + * indicated if more detailed information is not available or the person chooses not to reveal more + * information. */ + Appointment(2), + /** The person is physically away from all interactive communication devices. */ + Away(3), + /** The person is eating the first meal of the day, usually eaten in the morning. */ + Breakfast(4), + /** The person is busy, without further details. */ + Busy(5), + /** The person is having his or her main meal of the day, eaten in the evening or at midday. */ + Dinner(6), + /** This is a scheduled national or local holiday. */ + Holiday(7), + /** The person is riding in a vehicle, such as a car, but not steering. */ + InTransit(8), + /** The person is looking for (paid) work. */ + LookingForWork(9), + /** The person is eating his or her midday meal. */ + Lunch(10), + /** The person is scheduled for a meal, without specifying whether it is breakfast, lunch, or dinner, + * or some other meal. */ + Meal(11), + /** The person is in an assembly or gathering of people, as for a business, social, or religious purpose. + * A meeting is a sub-class of an appointment. */ + Meeting(12), + /** The person is talking on the telephone. */ + OnThePhone(13), + /** The person is engaged in an activity with no defined representation. A string describing the activity + * in plain text SHOULD be provided. */ + Other(14), + /** A performance is a sub-class of an appointment and includes musical, theatrical, and cinematic + * performances as well as lectures. It is distinguished from a meeting by the fact that the person + * may either be lecturing or be in the audience, with a potentially large number of other people, + * making interruptions particularly noticeable. */ + Performance(15), + /** The person will not return for the foreseeable future, e.g., because it is no longer working for + * the company. */ + PermanentAbsence(16), + /** The person is occupying himself or herself in amusement, sport, or other recreation. */ + Playing(17), + /** The person is giving a presentation, lecture, or participating in a formal round-table discussion. */ + Presentation(18), + /** The person is visiting stores in search of goods or services. */ + Shopping(19), + /** The person is sleeping.*/ + Sleeping(20), + /** The person is observing an event, such as a sports event. */ + Spectator(21), + /** The person is controlling a vehicle, watercraft, or plane. */ + Steering(22), + /** The person is on a business or personal trip, but not necessarily in-transit. */ + Travel(23), + /** The person is watching television. */ + TV(24), + /** The activity of the person is unknown. */ + Unknown(25), + /** A period of time devoted to pleasure, rest, or relaxation. */ + Vacation(26), + /** The person is engaged in, typically paid, labor, as part of a profession or job. */ + Working(27), + /** The person is participating in religious rites. */ + Worship(28), + Invalid(29); + + protected final int mValue; + + private PresenceActivityType(int value) { + mValue = value; + } + + public int toInt() { + return mValue; + } + + static protected PresenceActivityType fromInt(int value) { + switch (value) { + case 0: return Offline; + case 1: return Online; + case 2: return Appointment; + case 3: return Away; + case 4: return Breakfast; + case 5: return Busy; + case 6: return Dinner; + case 7: return Holiday; + case 8: return InTransit; + case 9: return LookingForWork; + case 10: return Lunch; + case 11: return Meal; + case 12: return Meeting; + case 13: return OnThePhone; + case 14: return Other; + case 15: return Performance; + case 16: return PermanentAbsence; + case 17: return Playing; + case 18: return Presentation; + case 19: return Shopping; + case 20: return Sleeping; + case 21: return Spectator; + case 22: return Steering; + case 23: return Travel; + case 24: return TV; + case 25: return Unknown; + case 26: return Vacation; + case 27: return Working; + case 28: return Worship; + default: return Invalid; + } + } +} diff --git a/java/common/org/linphone/core/PresenceBasicStatus.java b/java/common/org/linphone/core/PresenceBasicStatus.java new file mode 100644 index 000000000..cfdbadb5c --- /dev/null +++ b/java/common/org/linphone/core/PresenceBasicStatus.java @@ -0,0 +1,47 @@ +/* +PresenceBasicStatus.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +/** Basic status as defined in section 4.1.4 of RFC 3863 */ +public enum PresenceBasicStatus { + /** This value means that the associated contact element, if any, is ready to accept communication. */ + Open(0), + /** This value means that the associated contact element, if any, is unable to accept communication. */ + Closed(1), + Invalid(2); + + protected final int mValue; + + private PresenceBasicStatus(int value) { + mValue = value; + } + + public int toInt() { + return mValue; + } + + static protected PresenceBasicStatus fromInt(int value) { + switch (value) { + case 0: return Open; + case 1: return Closed; + default: return Invalid; + } + } +} diff --git a/java/common/org/linphone/core/PresenceModel.java b/java/common/org/linphone/core/PresenceModel.java new file mode 100644 index 000000000..78bc264c2 --- /dev/null +++ b/java/common/org/linphone/core/PresenceModel.java @@ -0,0 +1,173 @@ +/* +PresenceModel.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public interface PresenceModel { + + /** + * @brief Gets the basic status of a presence model. + * @return The #BasicStatus of the #PresenceModel object. + */ + PresenceBasicStatus getBasicStatus(); + + /** + * @brief Sets the basic status of a presence model. + * @param[in] basic_status The #BasicStatus to set for the #PresenceModel object. + * @return 0 if successful, a value < 0 in case of error. + */ + int setBasicStatus(PresenceBasicStatus basic_status); + + /** + * @brief Gets the timestamp of a presence model. + * @return The timestamp of the #LinphonePresenceModel object or -1 on error. + */ + long getTimestamp(); + + /** + * @brief Gets the contact of a presence model. + * @return A string containing the contact, or null if no contact is found. + */ + String getContact(); + + /** + * @brief Sets the contact of a presence model. + * @param contact The contact string to set. + */ + void setContact(String contact); + + /** + * @brief Gets the first activity of a presence model (there is usually only one). + * @return A #PresenceActivity object if successful, null otherwise. + */ + PresenceActivity getActivity(); + + /** + * @brief Sets the activity of a presence model (limits to only one activity). + * @param[in] activity The #PresenceActivityType to set for the model. + * @param[in] description An additional description of the activity to set for the model. Can be null if no additional description is to be added. + * @return 0 if successful, a value < 0 in case of error. + * + * WARNING: This method will modify the basic status of the model according to the activity being set. + * If you don't want the basic status to be modified automatically, you can use the combination of setBasicStatus(), clearActivities() and addActivity(). + */ + int setActivity(PresenceActivityType activity, String description); + + /** + * @brief Gets the number of activities included in the presence model. + * @return The number of activities included in the #PresenceModel object. + */ + long getNbActivities(); + + /** + * @brief Gets the nth activity of a presence model. + * @param idx The index of the activity to get (the first activity having the index 0). + * @return A #PresenceActivity object if successful, null otherwise. + */ + PresenceActivity getNthActivity(long idx); + + /** + * @brief Adds an activity to a presence model. + * @param[in] activity The #PresenceActivity to add to the model. + * @return 0 if successful, a value < 0 in case of error. + */ + int addActivity(PresenceActivity activity); + + /** + * @brief Clears the activities of a presence model. + * @return 0 if successful, a value < 0 in case of error. + */ + int clearActivities(); + + /** + * @brief Gets the first note of a presence model (there is usually only one). + * @param[in] lang The language of the note to get. Can be null to get a note that has no language specified or to get the first note whatever language it is written into. + * @return A #PresenceNote object if successful, null otherwise. + */ + PresenceNote getNote(String lang); + + /** + * @brief Adds a note to a presence model. + * @param[in] note_content The note to be added to the presence model. + * @param[in] lang The language of the note to be added. Can be null if no language is to be specified for the note. + * @return 0 if successful, a value < 0 in case of error. + * + * Only one note for each language can be set, so e.g. setting a note for the 'fr' language if there is only one will replace the existing one. + */ + int addNote(String note_content, String lang); + + /** + * @brief Clears all the notes of a presence model. + * @return 0 if successful, a value < 0 in case of error. + */ + int clearNotes(); + + /** + * @brief Gets the number of services included in the presence model. + * @return The number of services included in the #PresenceModel object. + */ + long getNbServices(); + + /** + * @brief Gets the nth service of a presence model. + * @param[in] idx The index of the service to get (the first service having the index 0). + * @return A #PresenceService object if successful, null otherwise. + */ + PresenceService getNthService(long idx); + + /** + * @brief Adds a service to a presence model. + * @param[in] service The #PresenceService object to add to the model. + * @return 0 if successful, a value < 0 in case of error. + */ + int addService(PresenceService service); + + /** + * @brief Clears the services of a presence model. + * @return 0 if successful, a value < 0 in case of error. + */ + int clearServices(); + + /** + * @brief Gets the number of persons included in the presence model. + * @return The number of persons included in the #PresenceModel object. + */ + long getNbPersons(); + + /** + * @brief Gets the nth person of a presence model. + * @param[in] idx The index of the person to get (the first person having the index 0). + * @return A pointer to a #PresencePerson object if successful, null otherwise. + */ + PresencePerson getNthPerson(long idx); + + /** + * @brief Adds a person to a presence model. + * @param[in] person The #PresencePerson object to add to the model. + * @return 0 if successful, a value < 0 in case of error. + */ + int addPerson(PresencePerson person); + + /** + * @brief Clears the persons of a presence model. + * @return 0 if successful, a value < 0 in case of error. + */ + int clearPersons(); + +} diff --git a/java/common/org/linphone/core/PresenceNote.java b/java/common/org/linphone/core/PresenceNote.java new file mode 100644 index 000000000..9353d9de4 --- /dev/null +++ b/java/common/org/linphone/core/PresenceNote.java @@ -0,0 +1,55 @@ +/* +PresenceNote.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public interface PresenceNote { + + /** + * @brief Gets the content of a presence note. + * @return A String with the content of the presence note. + */ + String getContent(); + + /** + * @brief Sets the content of a presence note. + * @param[in] content The content of the note. + * @return 0 if successful, a value < 0 in case of error. + */ + int setContent(String content); + + /** + * @brief Gets the language of a presence note. + * @return A String containing the language of the presence note, or null if no language is specified. + */ + String getLang(); + + /** + * @brief Sets the language of a presence note. + * @param[in] lang The language of the note. + * @return 0 if successful, a value < 0 in case of error. + */ + int setLang(String lang); + + /** + * @brief Gets the native pointer for this object. + */ + long getNativePtr(); + +} diff --git a/java/common/org/linphone/core/PresencePerson.java b/java/common/org/linphone/core/PresencePerson.java new file mode 100644 index 000000000..730aafe77 --- /dev/null +++ b/java/common/org/linphone/core/PresencePerson.java @@ -0,0 +1,120 @@ +/* +PresencePerson.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public interface PresencePerson { + + /** + * @brief Gets the id of a presence person. + * @return A string containing the id. + */ + String getId(); + + /** + * @brief Sets the id of a presence person. + * @param[in] id The id string to set. Can be null to generate it automatically. + * @return 0 if successful, a value < 0 in case of error. + */ + int setId(String id); + + /** + * @brief Gets the number of activities included in the presence person. + * @return The number of activities included in the #PresencePerson object. + */ + long getNbActivities(); + + /** + * @brief Gets the nth activity of a presence person. + * @param[in] idx The index of the activity to get (the first activity having the index 0). + * @return A #PresenceActivity object if successful, null otherwise. + */ + PresenceActivity getNthActivity(long idx); + + /** + * @brief Adds an activity to a presence person. + * @param[in] activity The #PresenceActivity object to add to the person. + * @return 0 if successful, a value < 0 in case of error. + */ + int addActivity(PresenceActivity activity); + + /** + * @brief Clears the activities of a presence person. + * @return 0 if successful, a value < 0 in case of error. + */ + int clearActivities(); + + /** + * @brief Gets the number of notes included in the presence person. + * @return The number of notes included in the #PresencePerson object. + */ + long getNbNotes(); + + /** + * @brief Gets the nth note of a presence person. + * @param[in] idx The index of the note to get (the first note having the index 0). + * @return A pointer to a #PresenceNote object if successful, null otherwise. + */ + PresenceNote getNthNote(long idx); + + /** + * @brief Adds a note to a presence person. + * @param[in] note The #PresenceNote object to add to the person. + * @return 0 if successful, a value < 0 in case of error. + */ + int addNote(PresenceNote note); + + /** + * @brief Clears the notes of a presence person. + * @return 0 if successful, a value < 0 in case of error. + */ + int clearNotes(); + + /** + * @brief Gets the number of activities notes included in the presence person. + * @return The number of activities notes included in the #PresencePerson object. + */ + long getNbActivitiesNotes(); + + /** + * @brief Gets the nth activities note of a presence person. + * @param[in] idx The index of the activities note to get (the first note having the index 0). + * @return A pointer to a #PresenceNote object if successful, null otherwise. + */ + PresenceNote getNthActivitiesNote(long idx); + + /** + * @brief Adds an activities note to a presence person. + * @param[in] note The #PresenceNote object to add to the person. + * @return 0 if successful, a value < 0 in case of error. + */ + int addActivitiesNote(PresenceNote note); + + /** + * @brief Clears the activities notes of a presence person. + * @return 0 if successful, a value < 0 in case of error. + */ + int clearActivitesNotes(); + + /** + * @brief Gets the native pointer for this object. + */ + long getNativePtr(); + +} diff --git a/java/common/org/linphone/core/PresenceService.java b/java/common/org/linphone/core/PresenceService.java new file mode 100644 index 000000000..3e06b6774 --- /dev/null +++ b/java/common/org/linphone/core/PresenceService.java @@ -0,0 +1,94 @@ +/* +PresenceService.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public interface PresenceService { + + /** + * @brief Gets the id of a presence service. + * @return A string containing the id. + */ + String getId(); + + /** + * @brief Sets the id of a presence service. + * @param[in] id The id string to set. Can be null to generate it automatically. + * @return 0 if successful, a value < 0 in case of error. + */ + int setId(String id); + + /** + * @brief Gets the basic status of a presence service. + * @return The #PresenceBasicStatus of the #PresenceService object. + */ + PresenceBasicStatus getBasicStatus(); + + /** + * @brief Sets the basic status of a presence service. + * @param[in] status The #PresenceBasicStatus to set for the #PresenceService object. + * @return 0 if successful, a value < 0 in case of error. + */ + int setBasicStatus(PresenceBasicStatus status); + + /** + * @brief Gets the contact of a presence service. + * @return A string containing the contact, or null if no contact is found. + */ + String getContact(); + + /** + * @brief Sets the contact of a presence service. + * @param[in] contact The contact string to set. + * @return 0 if successful, a value < 0 in case of error. + */ + int setContact(String contact); + + /** + * @brief Gets the number of notes included in the presence service. + * @return The number of notes included in the #PresenceService object. + */ + long getNbNotes(); + + /** + * @brief Gets the nth note of a presence service. + * @param[in] idx The index of the note to get (the first note having the index 0). + * @return A pointer to a #PresenceNote object if successful, null otherwise. + */ + PresenceNote getNthNote(long idx); + + /** + * @brief Adds a note to a presence service. + * @param[in] note The #PresenceNote object to add to the service. + * @return 0 if successful, a value < 0 in case of error. + */ + int addNote(PresenceNote note); + + /** + * @brief Clears the notes of a presence service. + * @return 0 if successful, a value < 0 in case of error. + */ + int clearNotes(); + + /** + * @brief Gets the native pointer for this object. + */ + long getNativePtr(); + +} diff --git a/java/common/org/linphone/core/Privacy.java b/java/common/org/linphone/core/Privacy.java new file mode 100644 index 000000000..59acc7565 --- /dev/null +++ b/java/common/org/linphone/core/Privacy.java @@ -0,0 +1,11 @@ +package org.linphone.core; + +public interface Privacy { + public static final int NONE=0; + public static final int USER=0x1; + public static final int HEADER=0x2; + public static final int SESSION=0x4; + public static final int ID=0x8; + public static final int CRITICAL=0x10; + public static final int DEFAULT=0x8000; +} diff --git a/java/common/org/linphone/core/PublishState.java b/java/common/org/linphone/core/PublishState.java new file mode 100644 index 000000000..7dfe86e3e --- /dev/null +++ b/java/common/org/linphone/core/PublishState.java @@ -0,0 +1,45 @@ +package org.linphone.core; + +public enum PublishState { + /** + * Initial state, should not be used. + */ + None(0), + /** + * Publish is in progress. + */ + Progress(1), + /** + * Publish succeeded. + */ + Ok(2), + /** + * Publish encountered an error. {@link LinphoneEvent.getReason()} gives more information about failure. + */ + Error(3), + /** + * Publish is about to expire. Application can trigger a refresh by calling {@link LinphoneCore.updatePublish()} + */ + Expiring(4), + /** + * Publish is terminated cleared. + */ + Cleared(5); + + protected final int mValue; + private PublishState(int value){ + mValue=value; + } + static protected PublishState fromInt(int value) throws LinphoneCoreException{ + switch(value){ + case 0: return None; + case 1: return Progress; + case 2: return Ok; + case 3: return Error; + case 4: return Expiring; + case 5: return Cleared; + default: + throw new LinphoneCoreException("Unhandled enum value "+value+" for PublishState"); + } + } +} diff --git a/java/common/org/linphone/core/Reason.java b/java/common/org/linphone/core/Reason.java index b07686aa2..8c954ab58 100644 --- a/java/common/org/linphone/core/Reason.java +++ b/java/common/org/linphone/core/Reason.java @@ -32,7 +32,23 @@ public class Reason { * Call not answered (in time). */ static public Reason Busy = new Reason(6,"Busy"); - + /** + * Incompatible media + * */ + static public Reason Media = new Reason(7,"Media"); + /** + * Transport error: connection failures, disconnections etc... + * */ + static public Reason IOError = new Reason(8,"IOError"); + /** + * Transport error: connection failures, disconnections etc... + * */ + static public Reason DoNotDisturb = new Reason(9,"DoNotDisturb"); + /** + * Operation not authorized because no credentials found + * */ + static public Reason Unauthorized = new Reason(10,"Unauthorized"); + protected final int mValue; private final String mStringValue; diff --git a/java/common/org/linphone/core/SubscriptionDir.java b/java/common/org/linphone/core/SubscriptionDir.java new file mode 100644 index 000000000..151bd4e15 --- /dev/null +++ b/java/common/org/linphone/core/SubscriptionDir.java @@ -0,0 +1,20 @@ +package org.linphone.core; + +import java.util.Vector; + +public enum SubscriptionDir { + Incoming(0), + Outgoing(1), + Invalid(2); + protected final int mValue; + private SubscriptionDir(int value){ + mValue=value; + } + static protected SubscriptionDir fromInt(int value){ + switch(value){ + case 0: return Incoming; + case 1: return Outgoing; + } + return Invalid; + } +} diff --git a/java/common/org/linphone/core/SubscriptionState.java b/java/common/org/linphone/core/SubscriptionState.java new file mode 100644 index 000000000..a6e84ec6a --- /dev/null +++ b/java/common/org/linphone/core/SubscriptionState.java @@ -0,0 +1,50 @@ +package org.linphone.core; + +public enum SubscriptionState { + /** + * Initial state, should not be used. + */ + None(0), + /** + * An outgoing subcription was created. + */ + OutoingInit(1), + /** + * An incoming subcription is received. + */ + IncomingReceived(2), + /** + * Subscription is pending, waiting for user approval + */ + Pending(3), + /** + * Subscription is accepted and now active. + */ + Active(4), + /** + * Subscription is terminated normally + */ + Terminated(5), + /** + * Subscription encountered an error, indicated by { @link LinphoneEvent.getReason() } + */ + Error(6); + + protected final int mValue; + private SubscriptionState(int value){ + mValue=value; + } + static protected SubscriptionState fromInt(int value) throws LinphoneCoreException{ + switch(value){ + case 0: return None; + case 1: return OutoingInit; + case 2: return IncomingReceived; + case 3: return Pending; + case 4: return Active; + case 5: return Terminated; + case 6: return Error; + default: + throw new LinphoneCoreException("Unhandled enum value "+value+" for SubscriptionState"); + } + } +} diff --git a/java/impl/org/linphone/core/LinphoneAddressImpl.java b/java/impl/org/linphone/core/LinphoneAddressImpl.java index 8d76da77a..9eee7ff4f 100644 --- a/java/impl/org/linphone/core/LinphoneAddressImpl.java +++ b/java/impl/org/linphone/core/LinphoneAddressImpl.java @@ -21,35 +21,59 @@ package org.linphone.core; public class LinphoneAddressImpl implements LinphoneAddress { + public enum WrapMode{ + FromNew, + FromConst, + FromExisting + }; protected final long nativePtr; - boolean ownPtr = false; private native long newLinphoneAddressImpl(String uri,String displayName); - private native void delete(long ptr); + private native long ref(long ptr); + private native void unref(long ptr); + private native long clone(long ptr); private native String getDisplayName(long ptr); private native String getUserName(long ptr); private native String getDomain(long ptr); private native String toUri(long ptr); private native void setDisplayName(long ptr,String name); + private native void setDomain(long ptr,String domain); + private native void setUserName(long ptr,String username); private native String toString(long ptr); - private native void setDomain(long ptr, String domain); - protected LinphoneAddressImpl(String identity) { + protected LinphoneAddressImpl(String identity) throws LinphoneCoreException{ nativePtr = newLinphoneAddressImpl(identity, null); + if(nativePtr==0) { + throw new LinphoneCoreException("Cannot create LinphoneAdress from ["+identity+"]"); + } } protected LinphoneAddressImpl(String username,String domain,String displayName) { - nativePtr = newLinphoneAddressImpl("sip:"+username+"@"+domain, displayName); + nativePtr = newLinphoneAddressImpl(null, displayName); + this.setUserName(username); + this.setDomain(domain); } - protected LinphoneAddressImpl(long aNativePtr,boolean javaOwnPtr) { - nativePtr = aNativePtr; - ownPtr=javaOwnPtr; + //this method is there because JNI is calling it. + private LinphoneAddressImpl(long aNativeptr){ + this(aNativeptr,WrapMode.FromConst); } - protected LinphoneAddressImpl(long aNativePtr) { - nativePtr = aNativePtr; - ownPtr=false; + protected LinphoneAddressImpl(long aNativePtr, WrapMode mode) { + switch(mode){ + case FromNew: + nativePtr=aNativePtr; + break; + case FromConst: + nativePtr=clone(aNativePtr); + break; + case FromExisting: + nativePtr=ref(aNativePtr); + break; + default: + nativePtr=0; + } } + protected void finalize() throws Throwable { - if (ownPtr) delete(nativePtr); + if (nativePtr!=0) unref(nativePtr); } public String getDisplayName() { return getDisplayName(nativePtr); @@ -95,7 +119,7 @@ public class LinphoneAddressImpl implements LinphoneAddress { throw new RuntimeException("Not implemented"); } public void setUserName(String username) { - throw new RuntimeException("Not implemented"); + setUserName(nativePtr,username); } } diff --git a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java index dee96fe5d..7d2b3dde2 100644 --- a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java +++ b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java @@ -32,19 +32,28 @@ class LinphoneAuthInfoImpl implements LinphoneAuthInfo { private native void setHa1(long ptr, String ha1); private native String getUserId(long ptr); private native String getHa1(long ptr); + private native String getDomain(long ptr); + private native void setDomain(long ptr, String domain); - protected LinphoneAuthInfoImpl(String username,String password, String realm) { - this(username,null,password,null,null); + boolean ownPtr = false; + protected LinphoneAuthInfoImpl(String username,String password, String realm, String domain) { + this(username, null, password, null, null, domain); } - protected LinphoneAuthInfoImpl(String username, String userid, String passwd, String ha1,String realm) { + protected LinphoneAuthInfoImpl(String username, String userid, String passwd, String ha1, String realm, String domain) { nativePtr = newLinphoneAuthInfo(); this.setUsername(username); this.setUserId(userid); this.setPassword(passwd); this.setHa1(ha1); + this.setDomain(domain); + ownPtr = true; + } + protected LinphoneAuthInfoImpl(long aNativePtr) { + nativePtr = aNativePtr; + ownPtr = false; } protected void finalize() throws Throwable { - delete(nativePtr); + if (ownPtr) delete(nativePtr); } public String getPassword() { return getPassword (nativePtr); @@ -82,4 +91,23 @@ class LinphoneAuthInfoImpl implements LinphoneAuthInfo { setHa1(nativePtr,ha1); } + @Override + public void setDomain(String domain) { + setDomain(nativePtr, domain); + } + @Override + public String getDomain() { + return getDomain(nativePtr); + } + + public LinphoneAuthInfo clone() { + LinphoneAuthInfo clone = LinphoneCoreFactory.instance().createAuthInfo( + getUsername(), + getUserId(), + getPassword(), + getHa1(), + getRealm(), + getDomain()); + return clone; + } } diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index 041acaef2..af79eb725 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -18,7 +18,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; - class LinphoneCallImpl implements LinphoneCall { protected final long nativePtr; @@ -81,7 +80,7 @@ class LinphoneCallImpl implements LinphoneCall { public LinphoneAddress getRemoteAddress() { long lNativePtr = getRemoteAddress(nativePtr); if (lNativePtr!=0) { - return new LinphoneAddressImpl(lNativePtr); + return new LinphoneAddressImpl(lNativePtr,LinphoneAddressImpl.WrapMode.FromConst); } else { return null; } @@ -207,4 +206,24 @@ class LinphoneCallImpl implements LinphoneCall { public void stopRecording() { stopRecording(nativePtr); } + private native int getTransferState(long nativePtr); + @Override + public State getTransferState() { + return State.fromInt(getTransferState(nativePtr)); + } + private native int sendInfoMessage(long callPtr, long msgptr); + @Override + public void sendInfoMessage(LinphoneInfoMessage msg) { + sendInfoMessage(nativePtr,((LinphoneInfoMessageImpl)msg).nativePtr); + } + private native Object getTransfererCall(long callPtr); + @Override + public LinphoneCall getTransfererCall() { + return (LinphoneCall)getTransfererCall(nativePtr); + } + private native Object getTransferTargetCall(long callPtr); + @Override + public LinphoneCall getTransferTargetCall() { + return (LinphoneCall)getTransferTargetCall(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneCallLogImpl.java b/java/impl/org/linphone/core/LinphoneCallLogImpl.java index 2419d74b3..7078a2a9f 100644 --- a/java/impl/org/linphone/core/LinphoneCallLogImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallLogImpl.java @@ -41,11 +41,11 @@ class LinphoneCallLogImpl implements LinphoneCallLog { } public LinphoneAddress getFrom() { - return new LinphoneAddressImpl(getFrom(nativePtr)); + return new LinphoneAddressImpl(getFrom(nativePtr),LinphoneAddressImpl.WrapMode.FromExisting); } public LinphoneAddress getTo() { - return new LinphoneAddressImpl(getTo(nativePtr)); + return new LinphoneAddressImpl(getTo(nativePtr),LinphoneAddressImpl.WrapMode.FromExisting); } public CallStatus getStatus() { return LinphoneCallLog.CallStatus.fromInt(getStatus(nativePtr)); diff --git a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java index 83cc95f54..aaafe9186 100644 --- a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java @@ -106,5 +106,17 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams { public String getCustomHeader(String name) { return getCustomHeader(nativePtr,name); } + + private native void setPrivacy(long nativePtr, int mask); + @Override + public void setPrivacy(int privacy_mask) { + setPrivacy(nativePtr,privacy_mask); + } + + private native int getPrivacy(long nativePtr); + @Override + public int getPrivacy() { + return getPrivacy(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 8162f67bf..8ce49c747 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -9,6 +9,11 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { private native void setExternalBodyUrl(long ptr, String url); private native long getFrom(long ptr); private native long getTime(long ptr); + private native int getStatus(long ptr); + private native boolean isRead(long ptr); + private native boolean isOutgoing(long ptr); + private native void store(long ptr); + private native int getStorageId(long ptr); protected LinphoneChatMessageImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -37,7 +42,7 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { @Override public LinphoneAddress getPeerAddress() { - return new LinphoneAddressImpl(getPeerAddress(nativePtr)); + return new LinphoneAddressImpl(getPeerAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } @Override @@ -52,7 +57,7 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { @Override public LinphoneAddress getFrom() { - return new LinphoneAddressImpl(getFrom(nativePtr)); + return new LinphoneAddressImpl(getFrom(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } private native void addCustomHeader(long nativePtr, String name, String value); @@ -69,4 +74,24 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public long getTime() { return getTime(nativePtr) * 1000; // Need milliseconds, not seconds } + + public LinphoneChatMessage.State getStatus() { + return LinphoneChatMessage.State.fromInt(getStatus(nativePtr)); + } + + public boolean isRead() { + return isRead(nativePtr); + } + + public boolean isOutgoing() { + return isOutgoing(nativePtr); + } + + public void store() { + store(nativePtr); + } + + public int getStorageId() { + return getStorageId(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 83141ad1c..7f4d684ee 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -18,6 +18,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.core; +import org.linphone.core.LinphoneChatMessage.State; import org.linphone.core.LinphoneChatMessage.StateListener; class LinphoneChatRoomImpl implements LinphoneChatRoom { @@ -26,13 +27,23 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native long getPeerAddress(long ptr); private native void sendMessage(long ptr, String message); private native void sendMessage2(long ptr, long message, StateListener listener); + private native long[] getHistory(long ptr, int limit); + private native void destroy(long ptr); + private native int getUnreadMessagesCount(long ptr); + private native void deleteHistory(long ptr); + private native void markAsRead(long ptr); + private native void deleteMessage(long room, long message); + private native void updateUrl(long room, long message); + private native long createLinphoneChatMessage2(long ptr, String message, + String url, int state, long timestamp, boolean isRead, + boolean isIncoming); protected LinphoneChatRoomImpl(long aNativePtr) { nativePtr = aNativePtr; } public LinphoneAddress getPeerAddress() { - return new LinphoneAddressImpl(getPeerAddress(nativePtr)); + return new LinphoneAddressImpl(getPeerAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } public void sendMessage(String message) { @@ -42,11 +53,60 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { @Override public void sendMessage(LinphoneChatMessage message, StateListener listener) { sendMessage2(nativePtr, message.getNativePtr(), listener); - } @Override public LinphoneChatMessage createLinphoneChatMessage(String message) { return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message)); } + + public LinphoneChatMessage[] getHistory() { + return getHistory(0); + } + + public LinphoneChatMessage[] getHistory(int limit) { + long[] typesPtr = getHistory(nativePtr, limit); + if (typesPtr == null) return null; + + LinphoneChatMessage[] messages = new LinphoneChatMessage[typesPtr.length]; + for (int i=0; i < messages.length; i++) { + messages[i] = new LinphoneChatMessageImpl(typesPtr[i]); + } + + return messages; + } + + public void destroy() { + destroy(nativePtr); + } + + public int getUnreadMessagesCount() { + return getUnreadMessagesCount(nativePtr); + } + + public void deleteHistory() { + deleteHistory(nativePtr); + } + + public void markAsRead() { + markAsRead(nativePtr); + } + + public void deleteMessage(LinphoneChatMessage message) { + if (message != null) + deleteMessage(nativePtr, message.getNativePtr()); + } + + public void updateUrl(LinphoneChatMessage message) { + if (message != null) + updateUrl(nativePtr, message.getNativePtr()); + } + + @Override + public LinphoneChatMessage createLinphoneChatMessage(String message, + String url, State state, long timestamp, boolean isRead, + boolean isIncoming) { + return new LinphoneChatMessageImpl(createLinphoneChatMessage2( + nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming)); + } } diff --git a/java/impl/org/linphone/core/LinphoneContentImpl.java b/java/impl/org/linphone/core/LinphoneContentImpl.java new file mode 100644 index 000000000..b12e6580f --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneContentImpl.java @@ -0,0 +1,69 @@ +package org.linphone.core; + +public class LinphoneContentImpl implements LinphoneContent { + private String mType, mSubtype, mEncoding; + private byte[] mData; + + public LinphoneContentImpl(String type, String subtype, byte data[], String encoding ){ + mType=type; + mSubtype=subtype; + mData=data; + mEncoding=encoding; + } + + @Override + public String getType() { + return mType; + } + + @Override + public String getSubtype() { + return mSubtype; + } + + @Override + public String getDataAsString() { + return new String(mData); + } + + @Override + public int getSize() { + return mData.length; + } + + @Override + public void setType(String type) { + mType=type; + } + + @Override + public void setSubtype(String subtype) { + mSubtype=subtype; + } + + @Override + public void setStringData(String data) { + mData=data.getBytes(); + } + + @Override + public void setData(byte data[]){ + mData=data; + } + + @Override + public String getEncoding() { + return mEncoding; + } + + @Override + public byte[] getData() { + return mData; + } + + @Override + public void setEncoding(String encoding) { + mEncoding=encoding; + } + +} diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 8cedba445..e526b47b5 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -21,7 +21,6 @@ package org.linphone.core; import java.io.File; import java.io.IOException; -import org.linphone.mediastream.CpuUtils; import org.linphone.mediastream.Version; import android.util.Log; @@ -39,60 +38,42 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } static { - // FFMPEG (audio/video) - loadOptionalLibrary("avutil"); - loadOptionalLibrary("swscale"); - loadOptionalLibrary("avcore"); - - System.loadLibrary("neon"); - - if (!hasNeonInCpuFeatures()) { - boolean noNeonLibrariesLoaded = loadOptionalLibrary("avcodecnoneon"); - if (!noNeonLibrariesLoaded) { - loadOptionalLibrary("avcodec"); - } - } else { - loadOptionalLibrary("avcodec"); + String eabi = "armeabi"; + if (Version.isX86()) { + eabi = "x86"; + } else if (Version.isArmv7()) { + eabi = "armeabi-v7a"; } - + + // FFMPEG (audio/video) + if (Version.isX86()) { + loadOptionalLibrary("avutil-linphone-x86"); + loadOptionalLibrary("swscale-linphone-x86"); + loadOptionalLibrary("avcodec-linphone-x86"); + } else if (Version.isArmv7()) { + loadOptionalLibrary("avutil-linphone-arm"); + loadOptionalLibrary("swscale-linphone-arm"); + loadOptionalLibrary("avcodec-linphone-arm"); + } + // OPENSSL (cryptography) - // lin prefix avoids collision with libs in /system/lib - loadOptionalLibrary("lincrypto"); - loadOptionalLibrary("linssl"); + // linphone suffix avoids collision with libs in /system/lib + loadOptionalLibrary("crypto-linphone-" + eabi); + loadOptionalLibrary("ssl-linphone-" + eabi); // Secure RTP and key negotiation - loadOptionalLibrary("srtp"); - loadOptionalLibrary("zrtpcpp"); // GPLv3+ - - // Tunnel - loadOptionalLibrary("tunnelclient"); - - // g729 A implementation - loadOptionalLibrary("bcg729"); + loadOptionalLibrary("srtp-" + eabi); + loadOptionalLibrary("zrtpcpp-" + eabi); // GPLv3+ //Main library - if (isArmv7()) { - if (hasNeonInCpuFeatures()) { - Log.d("linphone", "armv7 liblinphone loaded"); - System.loadLibrary("linphonearmv7"); - } else { - Log.w("linphone", "No-neon armv7 liblinphone loaded"); - System.loadLibrary("linphonearmv7noneon"); - } - } else if (Version.isX86()) { - Log.d("linphone", "No-neon x86 liblinphone loaded"); - System.loadLibrary("linphonex86"); - } else { - Log.d("linphone", "No-neon armv5 liblinphone loaded"); - System.loadLibrary("linphonearmv5noneon"); - } + System.loadLibrary("linphone-" + eabi); Version.dumpCapabilities(); } @Override public LinphoneAuthInfo createAuthInfo(String username, String password, - String realm) { - return new LinphoneAuthInfoImpl(username,password,realm); + String realm, String domain) { + return new LinphoneAuthInfoImpl(username, password, realm, domain); } @Override @@ -102,7 +83,7 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { } @Override - public LinphoneAddress createLinphoneAddress(String identity) { + public LinphoneAddress createLinphoneAddress(String identity) throws LinphoneCoreException { return new LinphoneAddressImpl(identity); } @@ -116,7 +97,9 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { String userConfig, String factoryConfig, Object userdata) throws LinphoneCoreException { try { - return new LinphoneCoreImpl(listener,new File(userConfig),new File(factoryConfig),userdata); + File user = userConfig == null ? null : new File(userConfig); + File factory = factoryConfig == null ? null : new File(factoryConfig); + return new LinphoneCoreImpl(listener, user, factory, userdata); } catch (IOException e) { throw new LinphoneCoreException("Cannot create LinphoneCore",e); } @@ -140,10 +123,11 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { @Override public native void setDebugMode(boolean enable, String tag); + + private native void _setLogHandler(Object handler); @Override public void setLogHandler(LinphoneLogHandler handler) { - //not implemented on Android - + _setLogHandler(handler); } @Override @@ -156,12 +140,6 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { return createLinphoneFriend(null); } - public static boolean hasNeonInCpuFeatures() - { - CpuUtils cpu = new CpuUtils(); - return cpu.isCpuNeon(); - } - public static boolean isArmv7() { return System.getProperty("os.arch").contains("armv7"); @@ -169,7 +147,45 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { @Override public LinphoneAuthInfo createAuthInfo(String username, String userid, - String passwd, String ha1, String realm) { - return new LinphoneAuthInfoImpl(username,userid,passwd,ha1,realm); + String passwd, String ha1, String realm, String domain) { + return new LinphoneAuthInfoImpl(username, userid, passwd, ha1, realm, domain); } + + @Override + public LinphoneContent createLinphoneContent(String type, String subType, + byte [] data, String encoding) { + return new LinphoneContentImpl(type,subType,data,encoding); + } + + @Override + public LinphoneContent createLinphoneContent(String type, String subType, + String data) { + return new LinphoneContentImpl(type,subType,data.getBytes(),null); + } + + @Override + public PresenceActivity createPresenceActivity(PresenceActivityType type, String description) { + return new PresenceActivityImpl(type, description); + } + + @Override + public PresenceService createPresenceService(String id, PresenceBasicStatus status, String contact) { + return new PresenceServiceImpl(id, status, contact); + } + + @Override + public PresenceModel createPresenceModel() { + return new PresenceModelImpl(); + } + + @Override + public PresenceModel createPresenceModel(PresenceActivityType type, String description) { + return new PresenceModelImpl(type, description); + } + + @Override + public PresenceModel createPresenceModel(PresenceActivityType type, String description, String note, String lang) { + return new PresenceModelImpl(type, description, note, lang); + } + } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index f9a7abf39..420547e57 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. package org.linphone.core; import static android.media.AudioManager.MODE_IN_CALL; -import static android.media.AudioManager.MODE_RINGTONE; import java.io.File; import java.io.IOException; @@ -45,10 +44,12 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setDefaultProxyConfig(long nativePtr,long proxyCfgNativePtr); private native int addProxyConfig(LinphoneProxyConfig jprtoxyCfg,long nativePtr,long proxyCfgNativePtr); + private native void removeProxyConfig(long nativePtr, long proxyCfg); private native void clearAuthInfos(long nativePtr); private native void clearProxyConfigs(long nativePtr); private native void addAuthInfo(long nativePtr,long authInfoNativePtr); + private native void removeAuthInfo(long nativePtr, long authInfoNativePtr); private native Object invite(long nativePtr,String uri); private native void terminateCall(long nativePtr, long call); private native long getRemoteAddress(long nativePtr); @@ -71,6 +72,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native boolean isMicMuted(long nativePtr); private native long findPayloadType(long nativePtr, String mime, int clockRate, int channels); private native int enablePayloadType(long nativePtr, long payloadType, boolean enable); + private native boolean isPayloadTypeEnabled(long nativePtr, long payloadType); private native void enableEchoCancellation(long nativePtr,boolean enable); private native boolean isEchoCancellationEnabled(long nativePtr); private native Object getCurrentCall(long nativePtr) ; @@ -80,10 +82,14 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setPreviewWindowId(long nativePtr, Object wid); private native void setDeviceRotation(long nativePtr, int rotation); private native void addFriend(long nativePtr,long friend); - private native void setPresenceInfo(long nativePtr,int minute_away, String alternative_contact,int status); - private native long createChatRoom(long nativePtr,String to); + private native void setPresenceInfo(long nativePtr, int minutes_away, String alternative_contact, int status); + private native int getPresenceInfo(long nativePtr); + private native void setPresenceModel(long nativePtr, long presencePtr); + private native Object getPresenceModel(long nativePtr); + private native long getOrCreateChatRoom(long nativePtr,String to); private native void enableVideo(long nativePtr,boolean vcap_enabled,boolean display_enabled); private native boolean isVideoEnabled(long nativePtr); + private native boolean isVideoSupported(long nativePtr); private native void setFirewallPolicy(long nativePtr, int enum_value); private native int getFirewallPolicy(long nativePtr); private native void setStunServer(long nativePtr, String stun_server); @@ -93,12 +99,15 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setUploadBandwidth(long nativePtr, int bw); private native void setDownloadBandwidth(long nativePtr, int bw); private native void setPreferredVideoSize(long nativePtr, int width, int heigth); + private native void setPreferredVideoSizeByName(long nativePtr, String name); private native int[] getPreferredVideoSize(long nativePtr); private native void setRing(long nativePtr, String path); private native String getRing(long nativePtr); private native void setRootCA(long nativePtr, String path); private native long[] listVideoPayloadTypes(long nativePtr); private native long[] getProxyConfigList(long nativePtr); + private native long[] getAuthInfosList(long nativePtr); + private native long findAuthInfos(long nativePtr, String username, String realm, String domain); private native long[] listAudioPayloadTypes(long nativePtr); private native void enableKeepAlive(long nativePtr,boolean enable); private native boolean isKeepAliveEnabled(long nativePtr); @@ -106,6 +115,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native int getSignalingTransportPort(long nativePtr, int code); private native void setSignalingTransportPorts(long nativePtr, int udp, int tcp, int tls); private native void enableIpv6(long nativePtr,boolean enable); + private native boolean isIpv6Enabled(long nativePtr); private native int pauseCall(long nativePtr, long callPtr); private native int pauseAllCalls(long nativePtr); private native int resumeCall(long nativePtr, long callPtr); @@ -130,13 +140,19 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setIncomingTimeout(long nativePtr, int timeout); private native void setInCallTimeout(long nativePtr, int timeout); private native void setPrimaryContact(long nativePtr, String displayName, String username); + private native String getPrimaryContactUsername(long nativePtr); + private native String getPrimaryContactDisplayName(long nativePtr); + private native void setChatDatabasePath(long nativePtr, String path); + private native long[] getChatRooms(long nativePtr); - LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException { - mListener=listener; - nativePtr = newLinphoneCore(listener,userConfig.getCanonicalPath(),factoryConfig.getCanonicalPath(),userdata); + LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig, File factoryConfig, Object userdata) throws IOException { + mListener = listener; + String user = userConfig == null ? null : userConfig.getCanonicalPath(); + String factory = factoryConfig == null ? null : factoryConfig.getCanonicalPath(); + nativePtr = newLinphoneCore(listener, user, factory, userdata); } LinphoneCoreImpl(LinphoneCoreListener listener) throws IOException { - mListener=listener; + mListener = listener; nativePtr = newLinphoneCore(listener,null,null,null); } @@ -161,6 +177,11 @@ class LinphoneCoreImpl implements LinphoneCore { addAuthInfo(nativePtr,((LinphoneAuthInfoImpl)info).nativePtr); } + public synchronized void removeAuthInfo(LinphoneAuthInfo info) { + isValid(); + removeAuthInfo(nativePtr,((LinphoneAuthInfoImpl)info).nativePtr); + } + public synchronized LinphoneProxyConfig getDefaultProxyConfig() { isValid(); long lNativePtr = getDefaultProxyConfig(nativePtr); @@ -191,10 +212,13 @@ class LinphoneCoreImpl implements LinphoneCore { throw new LinphoneCoreException("bad proxy config"); } } + public synchronized void removeProxyConfig(LinphoneProxyConfig proxyCfg) { + isValid(); + removeProxyConfig(nativePtr, ((LinphoneProxyConfigImpl)proxyCfg).nativePtr); + } public synchronized void clearAuthInfos() { isValid(); clearAuthInfos(nativePtr); - } public synchronized void clearProxyConfigs() { isValid(); @@ -210,7 +234,7 @@ class LinphoneCoreImpl implements LinphoneCore { if (ptr==0) { return null; } else { - return new LinphoneAddressImpl(ptr); + return new LinphoneAddressImpl(ptr,LinphoneAddressImpl.WrapMode.FromConst); } } public synchronized boolean isIncall() { @@ -261,7 +285,7 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized LinphoneAddress interpretUrl(String destination) throws LinphoneCoreException { long lAddress = interpretUrl(nativePtr,destination); if (lAddress != 0) { - return new LinphoneAddressImpl(lAddress,true); + return new LinphoneAddressImpl(lAddress,LinphoneAddressImpl.WrapMode.FromNew); } else { throw new LinphoneCoreException("Cannot interpret ["+destination+"]"); } @@ -301,6 +325,10 @@ class LinphoneCoreImpl implements LinphoneCore { } } + public synchronized boolean isPayloadTypeEnabled(PayloadType pt) { + isValid(); + return isPayloadTypeEnabled(nativePtr, ((PayloadTypeImpl)pt).nativePtr); + } public synchronized void enableEchoCancellation(boolean enable) { isValid(); enableEchoCancellation(nativePtr, enable); @@ -368,13 +396,21 @@ class LinphoneCoreImpl implements LinphoneCore { addFriend(nativePtr,((LinphoneFriendImpl)lf).nativePtr); } - public synchronized void setPresenceInfo(int minute_away, String alternative_contact, - OnlineStatus status) { - setPresenceInfo(nativePtr,minute_away,alternative_contact,status.mValue); + public synchronized void setPresenceInfo(int minutes_away, String alternative_contact, OnlineStatus status) { + setPresenceInfo(nativePtr,minutes_away,alternative_contact,status.mValue); } - public synchronized LinphoneChatRoom createChatRoom(String to) { - return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to)); + public synchronized OnlineStatus getPresenceInfo() { + return OnlineStatus.fromInt(getPresenceInfo(nativePtr)); + } + public synchronized void setPresenceModel(PresenceModel presence) { + setPresenceModel(nativePtr, ((PresenceModelImpl)presence).getNativePtr()); + } + public synchronized PresenceModel getPresenceModel() { + return (PresenceModel)getPresenceModel(nativePtr); + } + public synchronized LinphoneChatRoom getOrCreateChatRoom(String to) { + return new LinphoneChatRoomImpl(getOrCreateChatRoom(nativePtr,to)); } public synchronized void setPreviewWindow(Object w) { setPreviewWindowId(nativePtr,w); @@ -392,6 +428,9 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized boolean isVideoEnabled() { return isVideoEnabled(nativePtr); } + public synchronized boolean isVideoSupported() { + return isVideoSupported(nativePtr); + } public synchronized FirewallPolicy getFirewallPolicy() { return FirewallPolicy.fromInt(getFirewallPolicy(nativePtr)); } @@ -439,6 +478,10 @@ class LinphoneCoreImpl implements LinphoneCore { setPreferredVideoSize(nativePtr, vSize.width, vSize.height); } + public synchronized void setPreferredVideoSizeByName(String name) { + setPreferredVideoSizeByName(nativePtr, name); + } + public synchronized VideoSize getPreferredVideoSize() { int[] nativeSize = getPreferredVideoSize(nativePtr); @@ -526,6 +569,9 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void enableIpv6(boolean enable) { enableIpv6(nativePtr,enable); } + public synchronized boolean isIpv6Enabled() { + return isIpv6Enabled(nativePtr); + } public synchronized void adjustSoftwareVolume(int i) { //deprecated, does the same as setPlaybackGain(). } @@ -750,6 +796,15 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void setVideoPolicy(boolean autoInitiate, boolean autoAccept) { setVideoPolicy(nativePtr, autoInitiate, autoAccept); } + private native boolean getVideoAutoInitiatePolicy(long nativePtr); + public synchronized boolean getVideoAutoInitiatePolicy() { + return getVideoAutoInitiatePolicy(nativePtr); + } + private native boolean getVideoAutoAcceptPolicy(long nativePtr); + public synchronized boolean getVideoAutoAcceptPolicy() { + return getVideoAutoAcceptPolicy(nativePtr); + } + private native void setStaticPicture(long nativePtr, String path); public synchronized void setStaticPicture(String path) { setStaticPicture(nativePtr, path); @@ -858,15 +913,33 @@ class LinphoneCoreImpl implements LinphoneCore { setPrimaryContact(nativePtr, displayName, username); } + public synchronized String getPrimaryContactUsername() { + return getPrimaryContactUsername(nativePtr); + } + + public synchronized String getPrimaryContactDisplayName() { + return getPrimaryContactDisplayName(nativePtr); + } + private native void setUseSipInfoForDtmfs(long ptr, boolean use); public synchronized void setUseSipInfoForDtmfs(boolean use) { setUseSipInfoForDtmfs(nativePtr, use); } + private native boolean getUseSipInfoForDtmfs(long ptr); + public synchronized boolean getUseSipInfoForDtmfs() { + return getUseSipInfoForDtmfs(nativePtr); + } + private native void setUseRfc2833ForDtmfs(long ptr, boolean use); public synchronized void setUseRfc2833ForDtmfs(boolean use) { setUseRfc2833ForDtmfs(nativePtr, use); } + + private native boolean getUseRfc2833ForDtmfs(long ptr); + public synchronized boolean getUseRfc2833ForDtmfs() { + return getUseRfc2833ForDtmfs(nativePtr); + } private native long getConfig(long ptr); public synchronized LpConfig getConfig() { @@ -948,4 +1021,64 @@ class LinphoneCoreImpl implements LinphoneCore { public int getVideoDscp() { return getVideoDscp(nativePtr); } + + private native long createInfoMessage(long nativeptr); + @Override + public LinphoneInfoMessage createInfoMessage() { + return new LinphoneInfoMessageImpl(createInfoMessage(nativePtr)); + } + + private native Object subscribe(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, byte data [], String encoding); + @Override + public LinphoneEvent subscribe(LinphoneAddress resource, String eventname, + int expires, LinphoneContent content) { + return (LinphoneEvent)subscribe(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, eventname, expires, + content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getData() : null, + content!=null ? content.getEncoding() : null); + } + private native Object publish(long coreptr, long addrptr, String eventname, int expires, String type, String subtype, byte data [], String encoding); + @Override + public LinphoneEvent publish(LinphoneAddress resource, String eventname, + int expires, LinphoneContent content) { + return (LinphoneEvent)publish(nativePtr, ((LinphoneAddressImpl)resource).nativePtr, eventname, expires, + content!=null ? content.getType() : null, content!=null ? content.getSubtype() : null, content!=null ? content.getData() : null, + content!=null ? content.getEncoding() : null); + } + + public void setChatDatabasePath(String path) { + setChatDatabasePath(nativePtr, path); + } + + public synchronized LinphoneChatRoom[] getChatRooms() { + long[] typesPtr = getChatRooms(nativePtr); + if (typesPtr == null) return null; + + LinphoneChatRoom[] proxies = new LinphoneChatRoom[typesPtr.length]; + + for (int i=0; i < proxies.length; i++) { + proxies[i] = new LinphoneChatRoomImpl(typesPtr[i]); + } + + return proxies; + } + public LinphoneAuthInfo[] getAuthInfosList() { + long[] typesPtr = getAuthInfosList(nativePtr); + if (typesPtr == null) return null; + + LinphoneAuthInfo[] authInfos = new LinphoneAuthInfo[typesPtr.length]; + + for (int i=0; i < authInfos.length; i++) { + authInfos[i] = new LinphoneAuthInfoImpl(typesPtr[i]); + } + + return authInfos; + } + + public LinphoneAuthInfo findAuthInfo(String username, String realm, String domain) { + long ptr = findAuthInfos(nativePtr, username, realm, domain); + if (ptr == 0) + return null; + + return new LinphoneAuthInfoImpl(ptr); + } } diff --git a/java/impl/org/linphone/core/LinphoneEventImpl.java b/java/impl/org/linphone/core/LinphoneEventImpl.java new file mode 100644 index 000000000..9890f7cdf --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneEventImpl.java @@ -0,0 +1,91 @@ +package org.linphone.core; + +public class LinphoneEventImpl implements LinphoneEvent { + private Object mUserContext; + private long mNativePtr; + + protected LinphoneEventImpl(long nativePtr){ + mNativePtr=nativePtr; + } + + private native String getEventName(long nativeptr); + @Override + public String getEventName() { + return getEventName(mNativePtr); + } + + private native int acceptSubscription(long nativeptr); + @Override + public void acceptSubscription() { + acceptSubscription(mNativePtr); + } + + private native int denySubscription(long nativeptr, int reason); + @Override + public void denySubscription(Reason reason) { + denySubscription(mNativePtr,reason.mValue); + } + + private native int notify(long nativeptr, String type, String subtype, byte data[], String encoding); + @Override + public void notify(LinphoneContent content) { + notify(mNativePtr,content.getType(),content.getSubtype(),content.getData(),content.getEncoding()); + } + + private native int updateSubscribe(long nativePtr, String type, String subtype, byte data[], String encoding); + @Override + public void updateSubscribe(LinphoneContent content) { + updateSubscribe(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding()); + } + + private native int updatePublish(long nativePtr, String type, String subtype, byte data[], String encoding); + @Override + public void updatePublish(LinphoneContent content) { + updatePublish(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding()); + } + + private native int terminate(long nativePtr); + @Override + public void terminate() { + terminate(mNativePtr); + } + + private native int getReason(long nativePtr); + @Override + public Reason getReason() { + return Reason.fromInt(getReason(mNativePtr)); + } + + @Override + public void setUserContext(Object obj) { + mUserContext=obj; + } + + @Override + public Object getUserContext() { + return mUserContext; + } + + private native int getSubscriptionDir(long nativeptr); + @Override + public SubscriptionDir getSubscriptionDir() { + return SubscriptionDir.fromInt(getSubscriptionDir(mNativePtr)); + } + + private native int getSubscriptionState(long nativeptr); + @Override + public SubscriptionState getSubscriptionState() { + try { + return SubscriptionState.fromInt(getSubscriptionState(mNativePtr)); + } catch (LinphoneCoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return SubscriptionState.Error; + } + private native void unref(long nativeptr); + protected void finalize(){ + unref(mNativePtr); + } + +} diff --git a/java/impl/org/linphone/core/LinphoneFriendImpl.java b/java/impl/org/linphone/core/LinphoneFriendImpl.java index 6e7aa2db1..843170ce2 100644 --- a/java/impl/org/linphone/core/LinphoneFriendImpl.java +++ b/java/impl/org/linphone/core/LinphoneFriendImpl.java @@ -30,6 +30,8 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { private native void enableSubscribes(long nativePtr,boolean value); private native boolean isSubscribesEnabled(long nativePtr); private native int getStatus(long nativePtr); + private native Object getPresenceModel(long nativePtr); + private native void setPresenceModel(long nativePtr, long presencePtr); private native void edit(long nativePtr); private native void done(long nativePtr); @@ -52,7 +54,7 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { this.setAddress(nativePtr, ((LinphoneAddressImpl)anAddress).nativePtr); } public LinphoneAddress getAddress() { - return new LinphoneAddressImpl(getAddress(nativePtr)); + return new LinphoneAddressImpl(getAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } public void setIncSubscribePolicy(SubscribePolicy policy) { setIncSubscribePolicy(nativePtr,policy.mValue); @@ -69,6 +71,9 @@ class LinphoneFriendImpl implements LinphoneFriend, Serializable { public OnlineStatus getStatus() { return OnlineStatus.fromInt(getStatus(nativePtr)); } + public PresenceModel getPresenceModel() { + return (PresenceModel)getPresenceModel(nativePtr); + } public void edit() { edit(nativePtr); } diff --git a/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java b/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java new file mode 100644 index 000000000..7b9fad362 --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneInfoMessageImpl.java @@ -0,0 +1,41 @@ +package org.linphone.core; + +public class LinphoneInfoMessageImpl implements LinphoneInfoMessage { + protected long nativePtr; + private LinphoneContent mContent; + + private native Object getContent(long infoptr); + public LinphoneInfoMessageImpl(long ptr){ + nativePtr=ptr; + mContent=(LinphoneContent)getContent(nativePtr); + } + + private native void setContent(long nativePtr, String type, String subtype, String data); + @Override + public void setContent(LinphoneContent content) { + mContent=content; + setContent(nativePtr,mContent.getType(),mContent.getSubtype(),mContent.getDataAsString()); + } + + @Override + public LinphoneContent getContent() { + return mContent; + } + + private native void addHeader(long nativePtr, String name, String value); + @Override + public void addHeader(String name, String value) { + addHeader(nativePtr,name,value); + } + + private native String getHeader(long nativePtr, String name); + @Override + public String getHeader(String name) { + return getHeader(nativePtr,name); + } + + private native void delete(long nativePtr); + protected void finalize(){ + delete(nativePtr); + } +} diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 649d46fe3..dfa9c5170 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -30,12 +30,14 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { private native int getState(long nativePtr); private native void setExpires(long nativePtr, int delay); + private native int getExpires(long nativePtr); boolean ownPtr = false; protected LinphoneProxyConfigImpl(String identity,String proxy,String route, boolean enableRegister) throws LinphoneCoreException { nativePtr = newLinphoneProxyConfig(); setIdentity(identity); setProxy(proxy); + setRoute(route); enableRegister(enableRegister); ownPtr=true; } @@ -64,12 +66,14 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { private native boolean isRegistered(long ptr); private native void setDialPrefix(long ptr, String prefix); + private native String getDialPrefix(long ptr); private native String normalizePhoneNumber(long ptr,String number); private native String getDomain(long ptr); private native void setDialEscapePlus(long ptr, boolean value); + private native boolean getDialEscapePlus(long ptr); private native String getRoute(long ptr); private native int setRoute(long ptr,String uri); @@ -107,12 +111,18 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public void setDialPrefix(String prefix) { setDialPrefix(nativePtr, prefix); } + public String getDialPrefix() { + return getDialPrefix(nativePtr); + } public String getDomain() { return getDomain(nativePtr); } public void setDialEscapePlus(boolean value) { setDialEscapePlus(nativePtr,value); } + public boolean getDialEscapePlus() { + return getDialEscapePlus(nativePtr); + } public String getIdentity() { return getIdentity(nativePtr); } @@ -143,6 +153,9 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public void setExpires(int delay) { setExpires(nativePtr, delay); } + public int getExpires() { + return getExpires(nativePtr); + } public boolean publishEnabled() { return publishEnabled(nativePtr); } @@ -158,4 +171,20 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public int lookupCCCFromE164(String e164) { return lookupCCCFromE164(nativePtr, e164); } + private native int getReason(long nativeptr); + @Override + public Reason getError() { + return Reason.fromInt(getReason(nativePtr)); + } + private native void setPrivacy(long nativePtr, int mask); + @Override + public void setPrivacy(int privacy_mask) { + setPrivacy(nativePtr,privacy_mask); + } + + private native int getPrivacy(long nativePtr); + @Override + public int getPrivacy() { + return getPrivacy(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LpConfigImpl.java b/java/impl/org/linphone/core/LpConfigImpl.java index 6ca94b085..d2c24e93b 100644 --- a/java/impl/org/linphone/core/LpConfigImpl.java +++ b/java/impl/org/linphone/core/LpConfigImpl.java @@ -26,15 +26,17 @@ class LpConfigImpl implements LpConfig { boolean ownPtr = false; public LpConfigImpl(long ptr) { - nativePtr=ptr; + nativePtr = ptr; } private native long newLpConfigImpl(String file); private native void delete(long ptr); + public LpConfigImpl(String file) { nativePtr = newLpConfigImpl(file); ownPtr = true; } + protected void finalize() throws Throwable { if(ownPtr) { delete(nativePtr); @@ -42,13 +44,69 @@ class LpConfigImpl implements LpConfig { } private native void sync(long ptr); + @Override public void sync() { sync(nativePtr); } private native void setInt(long ptr, String section, String key, int value); + @Override public void setInt(String section, String key, int value) { setInt(nativePtr, section, key, value); } + private native void setFloat(long ptr, String section, String key, float value); + @Override + public void setFloat(String section, String key, float value) { + setFloat(nativePtr, section, key, value); + } + + private native void setBool(long ptr, String section, String key, boolean value); + @Override + public void setBool(String section, String key, boolean value) { + setBool(nativePtr, section, key, value); + } + + private native void setString(long ptr, String section, String key, String value); + @Override + public void setString(String section, String key, String value) { + setString(nativePtr, section, key, value); + } + + private native void setIntRange(long ptr, String section, String key, int min, int max); + @Override + public void setIntRange(String section, String key, int min, int max) { + setIntRange(nativePtr, section, key, min, max); + } + + private native int getInt(long ptr, String section, String key, int defaultValue); + @Override + public int getInt(String section, String key, int defaultValue) { + return getInt(nativePtr, section, key, defaultValue); + } + + private native float getFloat(long ptr, String section, String key, float defaultValue); + @Override + public float getFloat(String section, String key, float defaultValue) { + return getFloat(nativePtr, section, key, defaultValue); + } + + private native boolean getBool(long ptr, String section, String key, boolean defaultValue); + @Override + public boolean getBool(String section, String key, boolean defaultValue) { + return getBool(nativePtr, section, key, defaultValue); + } + + private native String getString(long ptr, String section, String key, String defaultValue); + @Override + public String getString(String section, String key, String defaultValue) { + return getString(nativePtr, section, key, defaultValue); + } + + private native int[] getIntRange(long ptr, String section, String key, int defaultMin, int defaultMax); + @Override + public int[] getIntRange(String section, String key, int defaultMin, int defaultMax) { + return getIntRange(nativePtr, section, key, defaultMin, defaultMax); + } + } diff --git a/java/impl/org/linphone/core/PayloadTypeImpl.java b/java/impl/org/linphone/core/PayloadTypeImpl.java index 864b094ff..436cd3f30 100644 --- a/java/impl/org/linphone/core/PayloadTypeImpl.java +++ b/java/impl/org/linphone/core/PayloadTypeImpl.java @@ -42,4 +42,26 @@ class PayloadTypeImpl implements PayloadType { public String toString() { return toString(nativePtr); } + + private native void setRecvFmtp(long ptr, String fmtp); + @Override + public void setRecvFmtp(String fmtp) { + setRecvFmtp(nativePtr,fmtp); + } + private native String getRecvFmtp(long ptr); + @Override + public String getRecvFmtp() { + return getRecvFmtp(nativePtr); + } + + private native void setSendFmtp(long ptr, String fmtp); + @Override + public void setSendFmtp(String fmtp) { + setSendFmtp(nativePtr,fmtp); + } + private native String getSendFmtp(long ptr); + @Override + public String getSendFmtp() { + return getSendFmtp(nativePtr); + } } diff --git a/java/impl/org/linphone/core/PresenceActivityImpl.java b/java/impl/org/linphone/core/PresenceActivityImpl.java new file mode 100644 index 000000000..281ecc9f2 --- /dev/null +++ b/java/impl/org/linphone/core/PresenceActivityImpl.java @@ -0,0 +1,72 @@ +/* +PresenceActivityImpl.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public class PresenceActivityImpl implements PresenceActivity { + private long mNativePtr; + + protected PresenceActivityImpl(long nativePtr) { + mNativePtr = nativePtr; + } + + private native long newPresenceActivityImpl(int type, String description); + protected PresenceActivityImpl(PresenceActivityType type, String description) { + mNativePtr = newPresenceActivityImpl(type.toInt(), description); + } + + private native void unref(long nativePtr); + protected void finalize() { + unref(mNativePtr); + } + + private native String toString(long nativePtr); + @Override + public String toString() { + return toString(mNativePtr); + } + + private native int getType(long nativePtr); + @Override + public PresenceActivityType getType() { + return PresenceActivityType.fromInt(getType(mNativePtr)); + } + + private native int setType(long nativePtr, int type); + @Override + public int setType(PresenceActivityType type) { + return setType(mNativePtr, type.toInt()); + } + + private native String getDescription(long nativePtr); + @Override + public String getDescription() { + return getDescription(mNativePtr); + } + + private native int setDescription(long nativePtr, String description); + @Override + public int setDescription(String description) { + return setDescription(mNativePtr, description); + } + + public long getNativePtr() { + return mNativePtr; + } +} diff --git a/java/impl/org/linphone/core/PresenceModelImpl.java b/java/impl/org/linphone/core/PresenceModelImpl.java new file mode 100644 index 000000000..b70ab6bd5 --- /dev/null +++ b/java/impl/org/linphone/core/PresenceModelImpl.java @@ -0,0 +1,185 @@ +/* +PresenceModelImpl.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public class PresenceModelImpl implements PresenceModel { + private long mNativePtr; + + protected PresenceModelImpl(long nativePtr) { + mNativePtr = nativePtr; + } + + private native long newPresenceModelImpl(); + protected PresenceModelImpl() { + mNativePtr = newPresenceModelImpl(); + } + + private native long newPresenceModelImpl(int type, String description); + protected PresenceModelImpl(PresenceActivityType type, String description) { + mNativePtr = newPresenceModelImpl(type.toInt(), description); + } + + private native long newPresenceModelImpl(int type, String description, String note, String lang); + protected PresenceModelImpl(PresenceActivityType type, String description, String note, String lang) { + mNativePtr = newPresenceModelImpl(type.toInt(), description, note, lang); + } + + private native void unref(long nativePtr); + protected void finalize() { + unref(mNativePtr); + } + + private native int getBasicStatus(long nativePtr); + @Override + public PresenceBasicStatus getBasicStatus() { + return PresenceBasicStatus.fromInt(getBasicStatus(mNativePtr)); + } + + private native int setBasicStatus(long nativePtr, int basic_status); + @Override + public int setBasicStatus(PresenceBasicStatus basic_status) { + return setBasicStatus(mNativePtr, basic_status.toInt()); + } + + private native long getTimestamp(long nativePtr); + @Override + public long getTimestamp() { + return getTimestamp(mNativePtr); + } + + private native String getContact(long nativePtr); + @Override + public String getContact() { + return getContact(mNativePtr); + } + + private native void setContact(long nativePtr, String contact); + @Override + public void setContact(String contact) { + setContact(mNativePtr, contact); + } + + private native Object getActivity(long nativePtr); + @Override + public PresenceActivity getActivity() { + return (PresenceActivity)getActivity(mNativePtr); + } + + private native int setActivity(long nativePtr, int activity, String description); + @Override + public int setActivity(PresenceActivityType activity, String description) { + return setActivity(mNativePtr, activity.toInt(), description); + } + + private native long getNbActivities(long nativePtr); + @Override + public long getNbActivities() { + return getNbActivities(mNativePtr); + } + + private native Object getNthActivity(long nativePtr, long idx); + @Override + public PresenceActivity getNthActivity(long idx) { + return (PresenceActivity)getNthActivity(mNativePtr, idx); + } + + private native int addActivity(long nativePtr, long activityPtr); + @Override + public int addActivity(PresenceActivity activity) { + return addActivity(mNativePtr, activity.getNativePtr()); + } + + private native int clearActivities(long nativePtr); + @Override + public int clearActivities() { + return clearActivities(mNativePtr); + } + + private native Object getNote(long nativePtr, String lang); + @Override + public PresenceNote getNote(String lang) { + return (PresenceNote)getNote(mNativePtr, lang); + } + + private native int addNote(long nativePtr, String note_content, String lang); + @Override + public int addNote(String note_content, String lang) { + return addNote(mNativePtr, note_content, lang); + } + + private native int clearNotes(long nativePtr); + @Override + public int clearNotes() { + return clearNotes(mNativePtr); + } + + private native long getNbServices(long nativePtr); + @Override + public long getNbServices() { + return getNbServices(mNativePtr); + } + + private native Object getNthService(long nativePtr, long idx); + @Override + public PresenceService getNthService(long idx) { + return (PresenceService)getNthService(mNativePtr, idx); + } + + private native int addService(long nativePtr, long servicePtr); + @Override + public int addService(PresenceService service) { + return addService(mNativePtr, service.getNativePtr()); + } + + private native int clearServices(long nativePtr); + @Override + public int clearServices() { + return clearServices(mNativePtr); + } + + private native long getNbPersons(long nativePtr); + @Override + public long getNbPersons() { + return getNbPersons(mNativePtr); + } + + private native Object getNthPerson(long nativePtr, long idx); + @Override + public PresencePerson getNthPerson(long idx) { + return (PresencePerson)getNthPerson(mNativePtr, idx); + } + + private native int addPerson(long nativePtr, long personPtr); + @Override + public int addPerson(PresencePerson person) { + return addPerson(mNativePtr, person.getNativePtr()); + } + + private native int clearPersons(long nativePtr); + @Override + public int clearPersons() { + return clearPersons(mNativePtr); + } + + public long getNativePtr() { + return mNativePtr; + } + +} diff --git a/java/impl/org/linphone/core/PresenceNoteImpl.java b/java/impl/org/linphone/core/PresenceNoteImpl.java new file mode 100644 index 000000000..113519c7f --- /dev/null +++ b/java/impl/org/linphone/core/PresenceNoteImpl.java @@ -0,0 +1,66 @@ +/* +PresenceNoteImpl.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public class PresenceNoteImpl implements PresenceNote { + private long mNativePtr; + + protected PresenceNoteImpl(long nativePtr) { + mNativePtr = nativePtr; + } + + private native long newPresenceNoteImpl(String content, String lang); + protected PresenceNoteImpl(String content, String lang) { + mNativePtr = newPresenceNoteImpl(content, lang); + } + + private native void unref(long nativePtr); + protected void finalize() { + unref(mNativePtr); + } + + private native String getContent(long nativePtr); + @Override + public String getContent() { + return getContent(mNativePtr); + } + + private native int setContent(long nativePtr, String content); + @Override + public int setContent(String content) { + return setContent(mNativePtr, content); + } + + private native String getLang(long nativePtr); + @Override + public String getLang() { + return getLang(mNativePtr); + } + + private native int setLang(long nativePtr, String lang); + @Override + public int setLang(String lang) { + return setLang(mNativePtr, lang); + } + + public long getNativePtr() { + return mNativePtr; + } +} diff --git a/java/impl/org/linphone/core/PresencePersonImpl.java b/java/impl/org/linphone/core/PresencePersonImpl.java new file mode 100644 index 000000000..7b7a336ac --- /dev/null +++ b/java/impl/org/linphone/core/PresencePersonImpl.java @@ -0,0 +1,126 @@ +/* +PresencePersonImpl.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public class PresencePersonImpl implements PresencePerson { + private long mNativePtr; + + protected PresencePersonImpl(long nativePtr) { + mNativePtr = nativePtr; + } + + private native long newPresencePersonImpl(String id); + protected PresencePersonImpl(String id) { + mNativePtr = newPresencePersonImpl(id); + } + + private native void unref(long nativePtr); + protected void finalize() { + unref(mNativePtr); + } + + private native String getId(long nativePtr); + @Override + public String getId() { + return getId(mNativePtr); + } + + private native int setId(long nativePtr, String id); + @Override + public int setId(String id) { + return setId(mNativePtr, id); + } + + private native long getNbActivities(long nativePtr); + @Override + public long getNbActivities() { + return getNbActivities(mNativePtr); + } + + private native Object getNthActivity(long nativePtr, long idx); + @Override + public PresenceActivity getNthActivity(long idx) { + return (PresenceActivity)getNthActivity(mNativePtr, idx); + } + + private native int addActivity(long nativePtr, long activityPtr); + @Override + public int addActivity(PresenceActivity activity) { + return addActivity(mNativePtr, activity.getNativePtr()); + } + + private native int clearActivities(long nativePtr); + @Override + public int clearActivities() { + return clearActivities(mNativePtr); + } + + private native long getNbNotes(long nativePtr); + @Override + public long getNbNotes() { + return getNbNotes(mNativePtr); + } + + private native Object getNthNote(long nativePtr, long idx); + @Override + public PresenceNote getNthNote(long idx) { + return (PresenceNote)getNthNote(mNativePtr, idx); + } + + private native int addNote(long nativePtr, long notePtr); + @Override + public int addNote(PresenceNote note) { + return addNote(mNativePtr, note.getNativePtr()); + } + + private native int clearNotes(long nativePtr); + @Override + public int clearNotes() { + return clearNotes(mNativePtr); + } + + private native long getNbActivitiesNotes(long nativePtr); + @Override + public long getNbActivitiesNotes() { + return getNbActivitiesNotes(mNativePtr); + } + + private native Object getNthActivitiesNote(long nativePtr, long idx); + @Override + public PresenceNote getNthActivitiesNote(long idx) { + return (PresenceNote)getNthActivitiesNote(mNativePtr, idx); + } + + private native int addActivitiesNote(long nativePtr, long notePtr); + @Override + public int addActivitiesNote(PresenceNote note) { + return addActivitiesNote(mNativePtr, note.getNativePtr()); + } + + private native int clearActivitesNotes(long nativePtr); + @Override + public int clearActivitesNotes() { + return clearActivitesNotes(mNativePtr); + } + + public long getNativePtr() { + return mNativePtr; + } +} diff --git a/java/impl/org/linphone/core/PresenceServiceImpl.java b/java/impl/org/linphone/core/PresenceServiceImpl.java new file mode 100644 index 000000000..29cd930e4 --- /dev/null +++ b/java/impl/org/linphone/core/PresenceServiceImpl.java @@ -0,0 +1,102 @@ +/* +PresenceServiceImpl.java +Copyright (C) 2010-2013 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +package org.linphone.core; + +public class PresenceServiceImpl implements PresenceService { + private long mNativePtr; + + protected PresenceServiceImpl(long nativePtr) { + mNativePtr = nativePtr; + } + + private native long newPresenceServiceImpl(String id, int status, String contact); + protected PresenceServiceImpl(String id, PresenceBasicStatus status, String contact) { + mNativePtr = newPresenceServiceImpl(id, status.toInt(), contact); + } + + private native void unref(long nativePtr); + protected void finalize() { + unref(mNativePtr); + } + + private native String getId(long nativePtr); + @Override + public String getId() { + return getId(mNativePtr); + } + + private native int setId(long nativePtr, String id); + @Override + public int setId(String id) { + return setId(mNativePtr, id); + } + + private native int getBasicStatus(long nativePtr); + @Override + public PresenceBasicStatus getBasicStatus() { + return PresenceBasicStatus.fromInt(getBasicStatus(mNativePtr)); + } + + private native int setBasicStatus(long nativePtr, int status); + @Override + public int setBasicStatus(PresenceBasicStatus status) { + return setBasicStatus(mNativePtr, status.toInt()); + } + + private native String getContact(long nativePtr); + @Override + public String getContact() { + return getContact(mNativePtr); + } + + private native int setContact(long nativePtr, String contact); + @Override + public int setContact(String contact) { + return setContact(mNativePtr, contact); + } + + private native long getNbNotes(long nativePtr); + @Override + public long getNbNotes() { + return getNbNotes(mNativePtr); + } + + private native Object getNthNote(long nativePtr, long idx); + @Override + public PresenceNote getNthNote(long idx) { + return (PresenceNote)getNthNote(mNativePtr, idx); + } + + private native int addNote(long nativePtr, long notePtr); + @Override + public int addNote(PresenceNote note) { + return addNote(mNativePtr, note.getNativePtr()); + } + + private native int clearNotes(long nativePtr); + @Override + public int clearNotes() { + return clearNotes(mNativePtr); + } + + public long getNativePtr() { + return mNativePtr; + } +} diff --git a/java/impl/org/linphone/tools/Xml2Lpc.java b/java/impl/org/linphone/tools/Xml2Lpc.java index 5e0a81880..8e3a9faa0 100644 --- a/java/impl/org/linphone/tools/Xml2Lpc.java +++ b/java/impl/org/linphone/tools/Xml2Lpc.java @@ -61,8 +61,9 @@ public class Xml2Lpc { // Load library static { - try { - System.loadLibrary("xml2"); + try { + new Xml2Lpc(); + //System.loadLibrary("xml2"); //System.loadLibrary("xml2lpc"); mAvailable = true; } catch (Throwable e) { diff --git a/linphone-deps.filelist b/linphone-deps.filelist index 98d759b14..53bab22af 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -1,13 +1,15 @@ ./bin/avcodec-53.dll +./bin/libspeex-1.dll +./bin/libspeexdsp-1.dll ./bin/avutil-51.dll ./bin/libeay32.dll ./bin/ssleay32.dll -./bin/libeXosip2-7.dll +./bin/libbellesip-0.dll +./bin/libantlr3c.dll +./lib/libpolarssl.dll ./bin/libogg-0.dll ./bin/libtheora-0.dll ./bin/libxml2-2.dll -./bin/libosip2-7.dll -./bin/libosipparser2-7.dll ./bin/swscale-2.dll ./bin/libsoup-2.4-1.dll ./bin/libgcrypt-11.dll @@ -16,3 +18,4 @@ ./bin/libtasn1-3.dll ./bin/libsqlite3-0.dll ./bin/libzrtpcpp.dll +./bin/libopus-0.dll diff --git a/linphone.spec.in b/linphone.spec.in index 86929b575..e8e7b68a6 100644 --- a/linphone.spec.in +++ b/linphone.spec.in @@ -11,7 +11,7 @@ Name: linphone Version: @VERSION@ -Release: %(git describe --tags --abbrev=40 | sed -rn 's/^.*-([0-9]+)-g[a-z0-9]{40}$/\1/p' || echo '1')%{?dist} +Release: %(version=`git describe --tags --abbrev=40 | sed -rn 's/^.*-([0-9]+)-g[a-z0-9]{40}$/\1/p'` && if test -z "$version" ; then echo 0 ; else echo $version ; fi)%{?dist} Summary: Phone anywhere in the whole world by using the Internet Group: Applications/Communications @@ -24,7 +24,7 @@ BuildArch: i686 %endif BuildRequires: gtk2-devel -BuildRequires: libeXosip2-devel speex-devel gettext +BuildRequires: belle-sip-devel speex-devel gettext BuildRequires: intltool gettext-devel %if %{video} BuildRequires: ffmpeg-devel SDL-devel @@ -47,16 +47,13 @@ Libraries and headers required to develop software with linphone. %prep %setup -q -#%patch -p 1 -b .pkgconfig -#%patch1 -p 1 -b .Werror -#%patch2 -p 1 -b .old %build %configure \ %if !%{video} --disable-video \ %endif - --docdir=%{_docdir} --enable-ipv6 --enable-static --enable-external-mediastreamer --enable-external-ortp + --disable-tests --docdir=%{_docdir} --enable-ipv6 --enable-static --enable-external-mediastreamer --enable-external-ortp %__make %{?_smp_mflags} @@ -85,7 +82,7 @@ rm -rf $RPM_BUILD_ROOT %defattr(-,root,root) %doc AUTHORS ChangeLog COPYING NEWS README TODO %{_bindir}/* -%{_libdir}/liblinphone.so.* +%{_libdir}/*.so.* %{_mandir}/* %{_datadir}/applications/%{name}.desktop %{_datadir}/pixmaps/linphone @@ -96,13 +93,17 @@ rm -rf $RPM_BUILD_ROOT %files devel %defattr(-,root,root) %{_includedir}/linphone -%{_libdir}/liblinphone.a -%{_libdir}/liblinphone.la -%{_libdir}/liblinphone.so +%{_libdir}/*.a +%{_libdir}/*.la +%{_libdir}/*.so %{_libdir}/pkgconfig/linphone.pc +%{_datadir}/tutorials/linphone/*.c %{_docdir} %changelog +* Mon Aug 19 2013 Jehan Monnier - 3.6.99 +- belle sip migration + * Wed Sep 28 2005 Francois-Xavier 'FiX' KOWALSKI - 1.2.0pre3 - Updated to latests Simon's work diff --git a/m4/ld-output-def.m4 b/m4/ld-output-def.m4 new file mode 100644 index 000000000..2dc6bf520 --- /dev/null +++ b/m4/ld-output-def.m4 @@ -0,0 +1,29 @@ +# ld-output-def.m4 serial 2 +dnl Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Simon Josefsson + +# gl_LD_OUTPUT_DEF() +# ------------- +# Check if linker supports -Wl,--output-def and define automake +# conditional HAVE_LD_OUTPUT_DEF if it is. +AC_DEFUN([gl_LD_OUTPUT_DEF], +[ + AC_CACHE_CHECK([if gcc/ld supports -Wl,--output-def], + [gl_cv_ld_output_def], + [if test "$enable_shared" = no; then + gl_cv_ld_output_def="not needed, shared libraries are disabled" + else + gl_ldflags_save=$LDFLAGS + LDFLAGS="-Wl,--output-def,conftest.def" + AC_LINK_IFELSE([AC_LANG_PROGRAM([])], + [gl_cv_ld_output_def=yes], + [gl_cv_ld_output_def=no]) + rm -f conftest.def + LDFLAGS="$gl_ldflags_save" + fi]) + AM_CONDITIONAL([HAVE_LD_OUTPUT_DEF], test "x$gl_cv_ld_output_def" = "xyes") +]) diff --git a/mediastreamer2 b/mediastreamer2 index 43b68b22c..6920f363d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 43b68b22cf8d0d1b0b5a064516d35899e5527358 +Subproject commit 6920f363d8f6db7c98f6dc471a045f43e4f26200 diff --git a/oRTP b/oRTP index 7c2805c2e..fcc51caa1 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 7c2805c2e2c1edadf9e9efe313d98f06c4c3614a +Subproject commit fcc51caa15def815189a388e878877a5354850e6 diff --git a/po/POTFILES.in b/po/POTFILES.in index 4a4497cbd..8f1c5d3a6 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -33,6 +33,5 @@ coreapi/presence.c coreapi/friend.c coreapi/proxy.c coreapi/callbacks.c -coreapi/sal_eXosip2.c coreapi/linphonecall.c diff --git a/po/POTFILES.skip b/po/POTFILES.skip index e254f124a..6b9ad1b55 100755 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -47,3 +47,4 @@ mediastreamer2/src/videofilters/winvideods.c mediastreamer2/src/videofilters/winvideo2.c mediastreamer2/src/videofilters/x11video.c mediastreamer2/src/voip/ice.c +build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs diff --git a/scripts/mk-ca-bundle.pl b/scripts/mk-ca-bundle.pl index edede4261..283ebd13c 100755 --- a/scripts/mk-ca-bundle.pl +++ b/scripts/mk-ca-bundle.pl @@ -36,7 +36,7 @@ use LWP::UserAgent; use strict; use vars qw($opt_b $opt_f $opt_h $opt_i $opt_l $opt_n $opt_q $opt_t $opt_u $opt_v $opt_w); -my $url = 'http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1'; +my $url = 'https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1'; # If the OpenSSL commandline is not in search path you can configure it here! my $openssl = 'openssl'; diff --git a/share/C/linphonecsh.1 b/share/C/linphonecsh.1 index 83271c5cb..9d02e4f87 100644 --- a/share/C/linphonecsh.1 +++ b/share/C/linphonecsh.1 @@ -56,6 +56,4 @@ By default a linphonec started as a daemon by 'linphonecsh init' does not use a Simon Morlat .SH "SEE ALSO" .LP -linphonec(1) sipomatic(1) linphone(1) -.TH
"" "" "Linux User's Manual" - +linphonec(1) linphone(1) diff --git a/share/Makefile.am b/share/Makefile.am index 6f8fe9198..85c1ab11b 100644 --- a/share/Makefile.am +++ b/share/Makefile.am @@ -31,13 +31,24 @@ pkgconfig_DATA=linphone.pc linphonedir=$(datadir)/linphone linphone_DATA=rootca.pem -rootca.pem: - $(top_srcdir)/scripts/mk-ca-bundle.pl rootca.pem + +#download root ca from mozilla using script from curl (mk-ca-bundle.pl). +#if that fails (no connection, no perl SSL...) , then a rootca bundle archived in the source tree is taken instead. +rootca.pem: + rm -f $(builddir)/fresh-rootca.pem + - HTTPS_CA_DIR=$(HTTPS_CA_DIR) $(top_srcdir)/scripts/mk-ca-bundle.pl $(builddir)/fresh-rootca.pem + if test -f $(builddir)/fresh-rootca.pem ; then \ + cp -f $(builddir)/fresh-rootca.pem $(builddir)/rootca.pem ; \ + else \ + cp -f $(srcdir)/archived-rootca.pem $(builddir)/rootca.pem ; \ + fi EXTRA_DIST = $(LINPHONE_SOUNDS) \ $(LINPHONE_RINGS) \ linphone.desktop.in \ linphone.pc.in \ Makefile.inc \ - rootca.pem + archived-rootca.pem + +CLEANFILES=rootca.pem diff --git a/share/archived-rootca.pem b/share/archived-rootca.pem new file mode 100644 index 000000000..24d7e4a80 --- /dev/null +++ b/share/archived-rootca.pem @@ -0,0 +1,3895 @@ +## +## ./fresh-rootca.pem -- Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Sat Dec 29 20:03:40 2012 +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## + +# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.87 $ $Date: 2012/12/29 16:32:45 $ + +GTE CyberTrust Global Root +========================== +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg +Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG +A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz +MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL +Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 +IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u +sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql +HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID +AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW +M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF +NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- + +Thawte Server CA +================ +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE +AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j +b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV +BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u +c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG +A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 +ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl +/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 +1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J +GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ +GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- + +Thawte Premium Server CA +======================== +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT +DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs +dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE +AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl +ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT +AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU +VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 +aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ +cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 +aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh +Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ +qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm +SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf +8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t +UCemDaYj+bvLpgcUQg== +-----END CERTIFICATE----- + +Equifax Secure CA +================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE +ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT +B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR +fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW +8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE +CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS +spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 +zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB +BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 +70+sB3c4 +-----END CERTIFICATE----- + +Digital Signature Trust Co. Global CA 1 +======================================= +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE +ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEy +MTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs +IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJE +NySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2i +o74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo +BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 +dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw +IoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQY +MBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAM +BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB +ACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEq +kzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4 +RbyhkwS7hp86W0N6w4pl +-----END CERTIFICATE----- + +Digital Signature Trust Co. Global CA 3 +======================================= +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE +ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEy +MDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs +IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUA +A4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGOD +VvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JS +xhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo +BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 +dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw +IoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQY +MBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAM +BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB +AEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfi +up/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1 +mPnHfxsb1gYgAlihw6ID +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA +TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah +WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf +Tqj/ZA1k +-----END CERTIFICATE----- + +Verisign Class 1 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgd +k4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIq +WpDBucSmFc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9ZrbWB85a7FkCMM +XErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2uluIncrKTdcu1OofdPvAbT6shkdHvC +lUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68DzFc6PLZ +-----END CERTIFICATE----- + +Verisign Class 2 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h +cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp +Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 +c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h +cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp +Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 +c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjx +nNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRC +wiNPStjwDqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEA +ATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/7aHmZuovCfTK +1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAXrXfMSTWqz9iP0b63GJZHc2pUIjRk +LbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnInjBJ7xUS0rg== +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G2 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz +dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO +FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 +lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB +MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT +1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD +Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 +-----END CERTIFICATE----- + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +======================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 +ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp +s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN +S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL +TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C +ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i +YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN +BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp +9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu +01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 +9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +ValiCert Class 1 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy +MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi +GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm +DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG +lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX +icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP +Orf1LXLI +-----END CERTIFICATE----- + +ValiCert Class 2 VA +=================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC +CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf +ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ +SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV +UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 +W9ViH0Pd +-----END CERTIFICATE----- + +RSA Root Certificate 1 +====================== +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp +b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs +YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh +bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw +MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 +d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg +UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 +LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td +3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H +BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs +3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF +V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r +on+jjBXu +-----END CERTIFICATE----- + +Verisign Class 1 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/E +bRrsC+MO8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJ +rKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7PoBMAGrgnoeS+ +Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP26KbqxzcSXKMpHgLZ2x87tNcPVkeB +FQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +q2aN17O6x5q25lXQBfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N +y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 +ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrspSCAaWihT37h +a88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/Pc +D98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== +-----END CERTIFICATE----- + +Verisign Class 2 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJBgNVBAYTAlVT +MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29y +azE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ug +b25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJ +BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 +c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y +aXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6 +tW8UvxDOJxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7 +C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQHgiBVrKtaaNS +0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjNqWm6o+sdDZykIKbBoMXRRkwXbdKs +Zj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0 +JhU8wI1NQ0kdvekhktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf +0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU +sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RIsH/7NiXaldDx +JBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//j +GHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 +EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc +cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw +EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj +055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f +j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 +xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa +t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +Verisign Class 4 Public Primary Certification Authority - G3 +============================================================ +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS +tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM +8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW +Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX +Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt +mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm +fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd +RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG +UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- + +Entrust.net Secure Server CA +============================ +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg +cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl +ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG +A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi +eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p +dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ +aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 +gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw +ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw +CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l +dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF +bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu +dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw +NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow +HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA +BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN +Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 +n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC +AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER +gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B +AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo +oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS +o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z +2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX +OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Equifax Secure Global eBusiness CA +================================== +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp +bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx +HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds +b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV +PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN +qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn +hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs +MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN +I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY +NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 1 +============================= +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB +LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE +ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz +IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ +1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a +IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk +MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW +Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF +AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 +lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ +KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- + +Equifax Secure eBusiness CA 2 +============================= +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UE +ChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y +MB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT +DkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn +2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5 +BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAG +A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUx +JjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoG +A1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9e +uSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMB +Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1 +jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia +78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUm +V+GRMOrN +-----END CERTIFICATE----- + +AddTrust Low-Value Services Root +================================ +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU +cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw +CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO +ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 +54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr +oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 +Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui +GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w +HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw +HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt +ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph +iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr +mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj +ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- + +AddTrust External Root +====================== +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD +VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw +NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU +cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg +Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 ++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw +Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo +aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy +2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 +7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL +VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk +VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl +j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 +e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u +G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +AddTrust Public Services Root +============================= +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU +cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ +BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l +dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu +nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i +d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG +Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw +HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G +A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G +A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 +JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL ++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 +Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H +EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- + +AddTrust Qualified Certificates Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU +cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx +CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ +IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx +64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 +KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o +L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR +wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU +MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE +BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y +azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG +GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze +RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB +iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +RSA Security 2048 v3 +==================== +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK +ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy +MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb +BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 +Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb +WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH +KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP ++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E +FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY +v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj +0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj +VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 +nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA +pKnXwiJPZ9d37CAFYd4= +-----END CERTIFICATE----- + +GeoTrust Global CA +================== +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw +MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo +BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet +8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc +T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU +vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk +DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q +zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 +d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 +mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p +XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm +Mw== +-----END CERTIFICATE----- + +GeoTrust Global CA 2 +==================== +-----BEGIN CERTIFICATE----- +MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw +MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j +LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ +NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k +LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA +Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b +HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH +K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 +srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh +ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL +OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC +x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF +H4z1Ir+rzoPz4iIprn2DQKi6bA== +-----END CERTIFICATE----- + +GeoTrust Universal CA +===================== +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 +MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu +Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t +JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e +RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs +7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d +8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V +qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga +Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB +Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu +KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 +ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 +XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB +hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 +qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL +oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK +xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF +KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 +DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK +xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU +p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI +P/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +GeoTrust Universal CA 2 +======================= +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN +R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 +MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg +SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 +DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 +j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q +JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a +QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 +WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP +20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn +ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC +SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG +8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 ++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E +BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ +4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ +mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq +A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg +Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP +pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d +FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp +gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm +X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +UTN-USER First-Network Applications +=================================== +-----BEGIN CERTIFICATE----- +MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCBozELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzAp +BgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5 +WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5T +YWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBB +cHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZVhawGNFug +mliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4Cj +DUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXu +Ozr0hAReYFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwi +P8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7igEL66S/ozjIE +j3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8w +HQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9j +cmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G +CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y +IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6LzsQCv4AdRWOOTK +RIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4Qp +xFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAq +DbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjisH8SE +-----END CERTIFICATE----- + +America Online Root Certification Authority 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG +v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z +DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh +sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP +8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z +o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf +GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF +VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft +3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g +Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- + +America Online Root Certification Authority 2 +============================================= +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT +QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG +A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg +T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en +fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 +f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO +qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN +RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 +gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn +6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid +FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 +Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj +B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op +aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY +T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p ++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg +JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy +zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO +ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh +1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf +GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff +Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP +cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= +-----END CERTIFICATE----- + +Visa eCommerce Root +=================== +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG +EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug +QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 +WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm +VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL +F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b +RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 +TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI +/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs +GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc +CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW +YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz +zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu +YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +Certum Root CA +============== +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK +ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla +Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u +by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x +wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL +kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ +89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K +Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P +NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ +GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg +GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ +0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS +qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +Comodo Secure Services root +=========================== +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw +MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu +Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi +BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP +9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc +rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC +oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V +p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E +FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj +YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm +aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm +4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL +DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw +pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H +RR3B7Hzs/Sk= +-----END CERTIFICATE----- + +Comodo Trusted Services root +============================ +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw +MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h +bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw +IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 +3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y +/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 +juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS +ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud +DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp +ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl +cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw +uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA +BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l +R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O +9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- + +QuoVadis Root CA +================ +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE +ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz +MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp +cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD +EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk +J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL +F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL +YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen +AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w +PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y +ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 +MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj +YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs +ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW +Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu +BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw +FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 +tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo +fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul +LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x +gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi +5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi +5nrQNiOKSnQ2+Q== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +Security Communication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP +U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw +8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM +DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX +5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd +DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 +JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g +0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a +mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ +s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ +6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- + +Sonera Class 1 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQw +NjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H88 +7dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9 +EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl +0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF645 +2F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW1ebZrgUa +HXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZT +iFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE9 +28Jj2VuXZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxV +yhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2nBBhjrZTOqMR +vq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2UvkVrCqIexVmiUefkl98HVrhq4uz2P +qYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9Z +IRlXvVWa +-----END CERTIFICATE----- + +Sonera Class 2 Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG +U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw +NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh +IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 +/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT +dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG +f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P +tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH +nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT +XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt +0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI +cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph +Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx +EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH +llpwrN9M +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA +============================= +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE +ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w +HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh +bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt +vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P +jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca +C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth +vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 +22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV +HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v +dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN +BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR +EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw +MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y +nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- + +TDC Internet Root CA +==================== +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE +ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx +NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu +ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j +xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL +znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc +5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 +otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI +AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM +VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM +MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC +AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe +UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G +CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m +gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ +2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb +O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU +Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- + +TDC OCES Root CA +================ +-----BEGIN CERTIFICATE----- +MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJESzEMMAoGA1UE +ChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5 +MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuH +nEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0 +zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvV +iGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBde +dObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO +3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB +5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5k +ay9yZXBvc2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBm +cmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4xLiBDZXJ0aWZp +Y2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4x +LjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEM +MAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYm +aHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy +MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647 ++RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6 +NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4 +A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYsc +A+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9 +AOoBmbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1 +AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2LqL19iUw== +-----END CERTIFICATE----- + +UTN DATACorp SGC Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ +BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa +MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w +HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy +dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys +raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo +wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA +9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv +33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud +DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 +BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD +LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 +DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 +I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx +EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP +DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- + +UTN USERFirst Email Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0 +BgNVBAMTLVVUTi1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05 +OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQx +FzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx +ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJz +dC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIx +B8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8 +om+rWV6lL8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHG +TPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZUOt4KpLoDd7Nl +yP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws6wIDAQABo4G5MIG2MAsGA1UdDwQE +AwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNV +HR8EUTBPME2gS6BJhkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGll +bnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH +AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u7mFVbwQ+zzne +xRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+ +5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarV +NZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZ +w7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= +-----END CERTIFICATE----- + +UTN USERFirst Hardware Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd +BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx +OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 +eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz +ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI +wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd +tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 +i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf +Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw +gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF +lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF +UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF +BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW +XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 +lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn +iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 +nfhmqA== +-----END CERTIFICATE----- + +UTN USERFirst Object Root CA +============================ +-----BEGIN CERTIFICATE----- +MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UE +BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl +IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAb +BgNVBAMTFFVUTi1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAz +NlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkx +HjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2Vy +dHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r5596Uj71VR +loTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQ +w5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vu +lBe3/IW+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7 +RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEAAaOBrzCBrDAL +BgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU2u1kdBScFDyr3ZmpvVsoTYs8 +ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly +c3QtT2JqZWN0LmNybDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQw +DQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw +NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNO +PmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFE +qmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCG +hU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= +-----END CERTIFICATE----- + +Camerfirma Chambers of Commerce Root +==================================== +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx +NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp +cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn +MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU +xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH +NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW +DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV +d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud +EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v +cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P +AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh +bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD +VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi +fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD +L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN +UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n +ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 +erfutGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- + +Camerfirma Global Chambersign Root +================================== +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe +QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i +ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx +NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt +YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg +MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw +ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J +1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O +by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl +6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c +8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ +BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j +aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B +Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj +aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y +ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA +PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y +gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ +PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 +IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes +t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- + +NetLock Qualified (Class QA) Root +================================= +-----BEGIN CERTIFICATE----- +MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQDEzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVn +eXpvaSAoQ2xhc3MgUUEpIFRhbnVzaXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0 +bG9jay5odTAeFw0wMzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTER +MA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0 +LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5ldExvY2sgTWlub3NpdGV0 +dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZhbnlraWFkbzEeMBwGCSqGSIb3DQEJARYP +aW5mb0BuZXRsb2NrLmh1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRV +CacbvWy5FPSKAtt2/GoqeKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e +8ia6AFQer7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO53Lhb +m+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWdvLrqOU+L73Sa58XQ +0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0lmT+1fMptsK6ZmfoIYOcZwvK9UdPM +0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4ICwDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV +HQ8BAf8EBAMCAQYwggJ1BglghkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2 +YW55IGEgTmV0TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh +biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQgZWxla3Ryb25p +a3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywgdmFsYW1pbnQgZWxmb2dhZGFz +YW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwg +YXogQWx0YWxhbm9zIFN6ZXJ6b2Rlc2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kg +ZWxqYXJhcyBtZWd0ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczov +L3d3dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0BuZXRsb2Nr +Lm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0 +aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMg +YXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0 +IGluZm9AbmV0bG9jay5uZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3 +DQEBBQUAA4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQMznN +wNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+NFAwLvt/MpqNPfMg +W/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCRVCHnpgu0mfVRQdzNo0ci2ccBgcTc +R08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR +5qq5aKrN9p2QdRLqOBrKROi3macqaJVmlaut74nLYKkGEsaUR+ko +-----END CERTIFICATE----- + +NetLock Notary (Class A) Root +============================= +-----BEGIN CERTIFICATE----- +MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI +EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j +ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX +DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH +EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD +VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz +cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM +D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ +z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC +/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 +tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 +4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG +A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC +Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv +bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu +IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn +LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 +ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz +IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh +IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu +b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg +Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp +bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 +ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP +ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB +CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr +KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM +8CgHrTwXZoi1/baI +-----END CERTIFICATE----- + +NetLock Business (Class B) Root +=============================== +-----BEGIN CERTIFICATE----- +MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg +VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD +VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv +bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg +VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S +o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr +1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV +HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ +RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh +dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 +ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv +c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg +YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh +c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz +Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA +bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl +IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 +YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj +cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM +43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR +stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI +-----END CERTIFICATE----- + +NetLock Express (Class C) Root +============================== +-----BEGIN CERTIFICATE----- +MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT +CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV +BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD +KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ +BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 +dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j +ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z +W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 +euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw +DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN +RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn +YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB +IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i +aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 +ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs +ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo +dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y +emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k +IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ +UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg +YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 +xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW +gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj +YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH +AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw +Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg +U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 +LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh +cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT +dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC +AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh +3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm +vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk +fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 +fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ +EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl +1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ +lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro +g14= +-----END CERTIFICATE----- + +Taiwan GRCA +=========== +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG +EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X +DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv +dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN +w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 +BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O +1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO +htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov +J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 +Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t +B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB +O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 +lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV +HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 +09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj +Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 +Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU +D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz +DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk +Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk +7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ +CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy ++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS +-----END CERTIFICATE----- + +Firmaprofesional Root CA +======================== +-----BEGIN CERTIFICATE----- +MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcT +GUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZp +Y2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FA +ZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTEL +MAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMT +OUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2 +ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5V +j1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJH +lShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf +3H5idPayBQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8 +NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZww +KgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAG +AQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD +ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq +u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdf +wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm +7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YG +VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA= +-----END CERTIFICATE----- + +Wells Fargo Root CA +=================== +-----BEGIN CERTIFICATE----- +MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV +BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl +bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv +MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX +x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3 +E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5 +OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j +sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj +YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF +BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD +ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv +m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R +OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx +x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023 +tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= +-----END CERTIFICATE----- + +Swisscom Root CA 1 +================== +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG +EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy +dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 +MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln +aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM +MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF +NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe +AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC +b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn +7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN +cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp +WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 +haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY +MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw +HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j +BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 +MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn +jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ +MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H +VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl +vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl +OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 +1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq +nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy +x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW +NY6E0F/6MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +Certplus Class 2 Primary CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE +BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN +OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy +dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR +5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ +Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO +YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e +e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME +CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ +YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t +L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD +P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R +TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ +7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW +//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +DST Root CA X3 +============== +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK +ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X +DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 +cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT +rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 +UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy +xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d +utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ +MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug +dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE +GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw +RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS +fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +DST ACES CA X6 +============== +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT +MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha +MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE +CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI +DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa +pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow +GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy +MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu +Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy +dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU +CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 +5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t +Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs +vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 +oKfN5XozNmr6mis= +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 1 +============================================== +-----BEGIN CERTIFICATE----- +MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP +MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 +acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx +MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg +U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB +TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC +aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX +yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i +Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ +8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 +W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME +BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 +sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE +q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy +B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY +nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H +-----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2 +============================================== +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN +MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr +dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G +A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls +acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe +LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI +x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g +QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr +5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB +AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt +Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ +hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P +9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 +UrbnBEI= +-----END CERTIFICATE----- + +SwissSign Platinum CA - G2 +========================== +-----BEGIN CERTIFICATE----- +MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWduIFBsYXRpbnVtIENBIC0gRzIw +HhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAwWjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMM +U3dpc3NTaWduIEFHMSMwIQYDVQQDExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu +669yIIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2HtnIuJpX+UF +eNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+6ixuEFGSzH7VozPY1kne +WCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5objM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIo +j5+saCB9bzuohTEJfwvH6GXp43gOCWcwizSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/6 +8++QHkwFix7qepF6w9fl+zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34T +aNhxKFrYzt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaPpZjy +domyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtFKwH3HBqi7Ri6Cr2D ++m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuWae5ogObnmLo2t/5u7Su9IPhlGdpV +CX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMBAAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCv +zAeHFUdvOMW0ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW +IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUAA4ICAQAIhab1 +Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0uMoI3LQwnkAHFmtllXcBrqS3 +NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4 +U99REJNi54Av4tHgvI42Rncz7Lj7jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8 +KV2LwUvJ4ooTHbG/u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl +9x8DYSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1puEa+S1B +aYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXaicYwu+uPyyIIoK6q8QNs +OktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbGDI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSY +Mdp08YSTcU1f+2BY0fvEwW2JorsgH51xkcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAci +IfNAChs0B0QTwoRqjt8ZWr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx +CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ +cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN +b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 +nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge +RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt +tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI +hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K +Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN +NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa +Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG +1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +thawte Primary Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 +MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg +SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv +KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT +FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs +oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ +1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc +q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K +aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p +afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF +AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE +uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 +jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH +z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G5 +============================================================ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh +dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt +YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz +j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD +Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ +Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r +fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv +Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG +SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ +X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE +KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC +Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE +ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +======================================= +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG +EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr +IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx +MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx +jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT +aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT +crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc +/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB +AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv +bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA +A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q +4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ +GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD +ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +WellsSecure Public Root Certificate Authority +============================================= +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM +F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw +NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN +MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl +bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD +VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 +iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 +i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 +bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB +K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB +AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu +cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm +lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB +i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww +GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI +K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 +bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj +qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es +E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ +tylv2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +IGC/A +===== +-----BEGIN CERTIFICATE----- +MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD +VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE +Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy +MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI +EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT +STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 +TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW +So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy +HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd +frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ +tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB +egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC +iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK +q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q +MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg +Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI +lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF +0mBWWg== +-----END CERTIFICATE----- + +Security Communication EV RootCA1 +================================= +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE +BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl +Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO +/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX +WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z +ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 +bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK +9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm +iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG +Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW +mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW +T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GA CA +=============================== +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE +BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG +A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH +bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD +VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw +IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 +IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 +Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg +Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD +d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ +/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R +LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm +MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 ++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY +okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= +-----END CERTIFICATE----- + +S-TRUST Authentication and Encryption Root CA 2005 PN +===================================================== +-----BEGIN CERTIFICATE----- +MIIEezCCA2OgAwIBAgIQNxkY5lNUfBq1uMtZWts1tzANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE +BhMCREUxIDAeBgNVBAgTF0JhZGVuLVd1ZXJ0dGVtYmVyZyAoQlcpMRIwEAYDVQQHEwlTdHV0dGdh +cnQxKTAnBgNVBAoTIERldXRzY2hlciBTcGFya2Fzc2VuIFZlcmxhZyBHbWJIMT4wPAYDVQQDEzVT +LVRSVVNUIEF1dGhlbnRpY2F0aW9uIGFuZCBFbmNyeXB0aW9uIFJvb3QgQ0EgMjAwNTpQTjAeFw0w +NTA2MjIwMDAwMDBaFw0zMDA2MjEyMzU5NTlaMIGuMQswCQYDVQQGEwJERTEgMB4GA1UECBMXQmFk +ZW4tV3VlcnR0ZW1iZXJnIChCVykxEjAQBgNVBAcTCVN0dXR0Z2FydDEpMCcGA1UEChMgRGV1dHNj +aGVyIFNwYXJrYXNzZW4gVmVybGFnIEdtYkgxPjA8BgNVBAMTNVMtVFJVU1QgQXV0aGVudGljYXRp +b24gYW5kIEVuY3J5cHRpb24gUm9vdCBDQSAyMDA1OlBOMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA2bVKwdMz6tNGs9HiTNL1toPQb9UY6ZOvJ44TzbUlNlA0EmQpoVXhOmCTnijJ4/Ob +4QSwI7+Vio5bG0F/WsPoTUzVJBY+h0jUJ67m91MduwwA7z5hca2/OnpYH5Q9XIHV1W/fuJvS9eXL +g3KSwlOyggLrra1fFi2SU3bxibYs9cEv4KdKb6AwajLrmnQDaHgTncovmwsdvs91DSaXm8f1Xgqf +eN+zvOyauu9VjxuapgdjKRdZYgkqeQd3peDRF2npW932kKvimAoA0SVtnteFhy+S8dF2g08LOlk3 +KC8zpxdQ1iALCvQm+Z845y2kuJuJja2tyWp9iRe79n+Ag3rm7QIDAQABo4GSMIGPMBIGA1UdEwEB +/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTVFJv +bmxpbmUxLTIwNDgtNTAdBgNVHQ4EFgQUD8oeXHngovMpttKFswtKtWXsa1IwHwYDVR0jBBgwFoAU +D8oeXHngovMpttKFswtKtWXsa1IwDQYJKoZIhvcNAQEFBQADggEBAK8B8O0ZPCjoTVy7pWMciDMD +pwCHpB8gq9Yc4wYfl35UvbfRssnV2oDsF9eK9XvCAPbpEW+EoFolMeKJ+aQAPzFoLtU96G7m1R08 +P7K9n3frndOMusDXtk3sU5wPBG7qNWdX4wple5A64U8+wwCSersFiXOMy6ZNwPv2AtawB6MDwidA +nwzkhYItr5pCHdDHjfhA7p0GVxzZotiAFP7hYy0yh9WUUpY6RsZxlj33mA6ykaqP2vROJAA5Veit +F7nTNCtKqUDMFypVZUF0Qn71wK/Ik63yGFs9iQzbRzkk+OBM8h+wPQrKBU6JIRrjKpms/H+h8Q8b +Hz2eBIPdltkdOpQ= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE +BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL +EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 +MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz +dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT +GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG +d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N +oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc +QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ +PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb +MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG +IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD +VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 +LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A +dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn +AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA +4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg +AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA +egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 +Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO +PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv +c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h +cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw +IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT +WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV +MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER +MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp +Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal +HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT +nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE +aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a +86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK +yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB +S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. +====================================== +-----BEGIN CERTIFICATE----- +MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT +AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg +LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w +HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ +U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh +IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN +yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU +2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 +4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP +2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm +8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf +HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa +Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK +5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b +czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g +ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF +BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug +cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf +AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX +EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v +/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 +MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 +3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk +eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f +/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h +RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU +Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 2 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw +MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw +IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 +xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ +Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u +SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G +dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ +KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj +TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP +JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk +vQ== +-----END CERTIFICATE----- + +TC TrustCenter Class 3 CA II +============================ +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy +IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw +MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 +c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE +AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W +yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo +6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ +uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk +2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB +7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 +Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU +cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i +SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE +O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 +yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 +IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal +092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc +5A== +-----END CERTIFICATE----- + +TC TrustCenter Universal CA I +============================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN +MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg +VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw +JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC +qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv +xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw +ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O +gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j +BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG +1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy +vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 +ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT +ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a +7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY +-----END CERTIFICATE----- + +Deutsche Telekom Root CA 2 +========================== +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT +RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG +A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 +MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G +A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS +b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 +bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI +KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY +AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK +Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV +jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV +HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr +E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy +zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 +rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G +dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +ComSign CA +========== +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0MRMwEQYDVQQD +EwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTMy +MThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMTCkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNp +Z24xCzAJBgNVBAYTAklMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49q +ROR+WCf4C9DklBKK8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTy +P2Q298CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb2CEJKHxN +GGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxCejVb7Us6eva1jsz/D3zk +YDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7KpiXd3DTKaCQeQzC6zJMw9kglcq/QytNuEM +rkvF7zuZ2SOzW120V+x0cAwqTwIDAQABo4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAy +oDCgLoYsaHR0cDovL2ZlZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0P +AQH/BAQDAgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRLAZs+ +VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWdfoPPbrxHbvUanlR2 +QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0McXS6hMTXcpuEfDhOZAYnKuGntewI +mbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb +/627HOkthIDYIb6FUtnUdLlphbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VG +zT2ouvDzuFYkRes3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U +AGegcQCCSA== +-----END CERTIFICATE----- + +ComSign Secured CA +================== +-----BEGIN CERTIFICATE----- +MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE +AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w +NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD +QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs +49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH +7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB +kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 +9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw +AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t +U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA +j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC +AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a +BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp +FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP +51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz +OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== +-----END CERTIFICATE----- + +Cybertrust Global Root +====================== +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li +ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 +MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD +ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW +0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL +AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin +89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT +8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 +MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G +A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO +lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi +5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 +hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T +X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 +============================================================================================================================= +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH +DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q +aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry +b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV +BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg +S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 +MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl +IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF +n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl +IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft +dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl +cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO +Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 +xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR +6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd +BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 +N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT +y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh +LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M +dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= +-----END CERTIFICATE----- + +Buypass Class 2 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 +MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M +cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 +0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 +0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R +uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV +1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt +7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 +fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w +wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- + +Buypass Class 3 CA 1 +==================== +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 +MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh +c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx +ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 +n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia +AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c +1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P +AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 +pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA +EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 +htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj +el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 +-----END CERTIFICATE----- + +EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 +========================================================================== +-----BEGIN CERTIFICATE----- +MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg +QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe +Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p +ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt +IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by +X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b +gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr +eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ +TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy +Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn +uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI +qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm +ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 +Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW +Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t +FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm +zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k +XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT +bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU +RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK +1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt +2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ +Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 +AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +CNNIC ROOT +========== +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE +ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw +OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD +o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz +VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT +VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or +czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK +y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC +wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S +lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 +Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM +O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 +BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 +G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m +mxE= +-----END CERTIFICATE----- + +ApplicationCA - Japanese Government +=================================== +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT +SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw +MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl +cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 +fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN +wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE +jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu +nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU +WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV +BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD +vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs +o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g +/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD +io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW +dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G3 +============================================= +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 +IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy +eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz +NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo +YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT +LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j +K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE +c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C +IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu +dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr +2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 +cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE +Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s +t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +thawte Primary Root CA - G2 +=========================== +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC +VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu +IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg +Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV +MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG +b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt +IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS +LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 +8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU +mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN +G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K +rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +thawte Primary Root CA - G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE +BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 +aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w +ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD +VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG +A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At +P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC ++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY +7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW +vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ +KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK +A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC +8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm +er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G2 +============================================= +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 +OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl +b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG +BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc +KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ +EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m +ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 +npaqBA+K +-----END CERTIFICATE----- + +VeriSign Universal Root Certification Authority +=============================================== +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO +ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk +IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv +cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj +1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP +MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 +9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I +AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR +tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G +CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O +a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 +Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx +Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx +P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P +wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 +mJO37M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G4 +============================================================ +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 +b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz +ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo +b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 +Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz +rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw +HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u +Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD +A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx +AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +============================================ +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G2 +================================== +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE +CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g +Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC +TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l +ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ +5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn +vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj +CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil +e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR +OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI +CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 +48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi +trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 +qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB +AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC +ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA +A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz ++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj +f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN +kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk +CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF +URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb +CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h +oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV +IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm +66+KAQ== +-----END CERTIFICATE----- + +CA Disig +======== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK +QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw +MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz +bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm +GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD +Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo +hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt +ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w +gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P +AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz +aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff +ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa +BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t +WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 +mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ +CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K +ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA +4Z7CRneC9VkGjCFMhwnN5ag= +-----END CERTIFICATE----- + +Juur-SK +======= +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA +c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw +DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG +SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy +aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf +TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC ++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw +UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa +Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF +MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD +HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh +AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA +cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr +AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw +cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE +FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G +A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo +ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL +abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 +IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh +Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 +yyqcjg== +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +======================= +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT +DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx +NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n +IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 +ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr +auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh +qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY +V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV +HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i +h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio +l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei +IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps +T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT +c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +ACEDICOM Root +============= +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD +T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 +MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG +A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk +WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD +YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew +MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb +m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk +HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT +xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 +3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 +2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq +TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz +4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU +9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv +bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg +aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP +eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk +zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 +ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI +KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq +nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE +I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp +MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o +tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== +-----END CERTIFICATE----- + +Verisign Class 1 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAx +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0fzGVuDLDQ +VoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHiTkVWaR94AoDa3EeRKbs2 +yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFgVKTk8d6Pa +XCUDfGD67gmZPCcQcMgMCeazh88K4hiWNWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n +0a3hUKw8fGJLj7qE1xIVGx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZ +RjXZ+Hxb +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority +======================================================= +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow +XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 +f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol +hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky +CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX +bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ +D/xwzoiQ +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi +=================================================== +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz +ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 +MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 +cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u +aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY +8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y +jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI +JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk +9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG +SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d +F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq +D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 +Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq +fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +TC TrustCenter Universal CA III +=============================== +-----BEGIN CERTIFICATE----- +MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UEBhMC +REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy +IFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAe +Fw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNU +QyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0Ex +KDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF5+cvAqBNLaT6hdqbJYUt +QCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYvDIRlzg9uwliT6CwLOunBjvvya8o84pxO +juT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+Eut +CHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1 +M4BDj5yjdipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8G +A1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEA +g8ev6n9NCjw5sWi+e22JLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+ +KGwWaODIl0YgoGhnYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhK +BgePxLcHsU0GDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV +CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIq +woIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud +EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH +DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA +bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx +ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx +51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk +R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP +T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f +Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl +osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR +crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR +saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD +KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi +6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Chambers of Commerce Root - 2008 +================================ +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy +Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl +ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF +EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl +cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA +XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj +h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ +ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk +NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g +D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 +lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ +0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 +EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI +G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ +BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh +bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh +bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC +CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH +AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 +wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH +3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU +RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 +M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 +YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF +9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK +zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG +nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ +-----END CERTIFICATE----- + +Global Chambersign Root - 2008 +============================== +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD +MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv +bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu +QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx +NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg +Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ +QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf +VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf +XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 +ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB +/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA +TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M +H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe +Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF +HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB +AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT +BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE +BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm +aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm +aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp +1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 +dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG +/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 +ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s +dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg +9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH +foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du +qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr +P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq +c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +Certinomis - Autorité Racine +============================= +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK +Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg +LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG +A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw +JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa +wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly +Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw +2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N +jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q +c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC +lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb +xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g +530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna +4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x +WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva +R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 +nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B +CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv +JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE +qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b +WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE +wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ +vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- + +Root CA Generalitat Valenciana +============================== +-----BEGIN CERTIFICATE----- +MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE +ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 +IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 +WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE +CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 +F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B +ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ +D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte +JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB +AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n +dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB +ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl +AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA +YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy +AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA +aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt +AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA +YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu +AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA +OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 +dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV +BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G +A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S +b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh +TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz +Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 +NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH +iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt ++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= +-----END CERTIFICATE----- + +A-Trust-nQual-03 +================ +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE +Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy +a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R +dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw +RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 +ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 +c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA +zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n +yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE +SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 +iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V +cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV +eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 +ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr +sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd +JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS +mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 +ahq97BvIxYSazQ== +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +====== +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE +BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w +ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD +VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE +CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT +BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 +MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt +SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl +Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh +cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK +w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT +ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 +HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a +E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw +0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD +VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 +Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l +dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ +lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa +Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe +l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 +E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D +5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +======================================================= +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT +O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y +aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT +AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z +IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo +IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI +1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa +71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u +8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH +3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ +MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 +MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu +b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt +XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD +/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N +7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Trustis FPS Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 +IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV +BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ +RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk +H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa +cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt +o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA +AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd +BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c +GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC +yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P +8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV +l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl +iB6XzCGcKQENZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +StartCom Certification Authority +================================ +-----BEGIN CERTIFICATE----- +MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu +ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 +NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk +LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg +U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y +o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ +Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d +eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt +2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z +6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ +osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ +untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc +UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT +37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ +Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 +dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu +c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv +bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 +aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG +cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 +fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm +N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN +Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T +tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX +e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA +2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs +HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE +JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib +D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= +-----END CERTIFICATE----- + +StartCom Certification Authority G2 +=================================== +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN +U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE +ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O +o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG +4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi +Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul +Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs +O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H +vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L +nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS +FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa +z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ +KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K +2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk +J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ +JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG +/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc +nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld +blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc +l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm +7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm +obp573PYtlNXLfbQ4ddI +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +EE Certification Centre Root CA +=============================== +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG +EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy +dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw +MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB +UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy +ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM +TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 +rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw +93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN +P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ +MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF +BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj +xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM +lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU +3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM +dcGWxZ0= +-----END CERTIFICATE----- diff --git a/tester/Makefile.am b/tester/Makefile.am new file mode 100644 index 000000000..e81c85d97 --- /dev/null +++ b/tester/Makefile.am @@ -0,0 +1,40 @@ +EXTRA_DIST= empty_rc laure_rc marie_early_rc marie_no_sdp_rc marie_rc multi_account_lrc pauline_alt_rc \ + pauline_rc pauline_wild_rc tester_hosts sounds images certificates + + +if BUILD_CUNIT_TESTS + +noinst_PROGRAMS=liblinphone_tester + +liblinphone_tester_SOURCES= liblinphone_tester.c liblinphone_tester.h\ + setup_tester.c \ + register_tester.c \ + message_tester.c \ + call_tester.c \ + presence_tester.c \ + upnp_tester.c \ + eventapi_tester.c + + +#liblinphone_tester_CFLAGS=$(CUNIT_CFLAGS) + +#liblinphone_tester_LDFLAGS=$(CUNIT_LIBS) + + +AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/coreapi + +LDADD=$(top_builddir)/coreapi/liblinphone.la + +AM_LDFLAGS=$(CUNIT_LIBS) + +AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) + +test: liblinphone_tester + ./liblinphone_tester --config $(abs_srcdir) + +else + +test: + @echo "CUnit must be installed to be able to run the tests!" + +endif diff --git a/tester/call_tester.c b/tester/call_tester.c new file mode 100644 index 000000000..b166cb86e --- /dev/null +++ b/tester/call_tester.c @@ -0,0 +1,1474 @@ +/* + belle-sip - SIP (RFC3261) library. + 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 3 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, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" + + +void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ + char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); + char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); + stats* counters; + ms_message(" %s call from [%s] to [%s], new state is [%s]" ,linphone_call_get_call_log(call)->dir==LinphoneCallIncoming?"Incoming":"Outgoing" + ,from + ,to + ,linphone_call_state_to_string(cstate)); + ms_free(to); + ms_free(from); + counters = get_stats(lc); + switch (cstate) { + case LinphoneCallIncomingReceived:counters->number_of_LinphoneCallIncomingReceived++;break; + case LinphoneCallOutgoingInit :counters->number_of_LinphoneCallOutgoingInit++;break; + case LinphoneCallOutgoingProgress :counters->number_of_LinphoneCallOutgoingProgress++;break; + case LinphoneCallOutgoingRinging :counters->number_of_LinphoneCallOutgoingRinging++;break; + case LinphoneCallOutgoingEarlyMedia :counters->number_of_LinphoneCallOutgoingEarlyMedia++;break; + case LinphoneCallConnected :counters->number_of_LinphoneCallConnected++;break; + case LinphoneCallStreamsRunning :counters->number_of_LinphoneCallStreamsRunning++;break; + case LinphoneCallPausing :counters->number_of_LinphoneCallPausing++;break; + case LinphoneCallPaused :counters->number_of_LinphoneCallPaused++;break; + case LinphoneCallResuming :counters->number_of_LinphoneCallResuming++;break; + case LinphoneCallRefered :counters->number_of_LinphoneCallRefered++;break; + case LinphoneCallError :counters->number_of_LinphoneCallError++;break; + case LinphoneCallEnd :counters->number_of_LinphoneCallEnd++;break; + case LinphoneCallPausedByRemote :counters->number_of_LinphoneCallPausedByRemote++;break; + case LinphoneCallUpdatedByRemote :counters->number_of_LinphoneCallUpdatedByRemote++;break; + case LinphoneCallIncomingEarlyMedia :counters->number_of_LinphoneCallIncomingEarlyMedia++;break; + case LinphoneCallUpdating :counters->number_of_LinphoneCallUpdating++;break; + case LinphoneCallReleased :counters->number_of_LinphoneCallReleased++;break; + default: + CU_FAIL("unexpected event");break; + } +} + +void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) { + char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to); + char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from); + stats* counters; + ms_message("Transferred call from [%s] to [%s], new state is [%s]",from,to,linphone_call_state_to_string(new_call_state)); + ms_free(to); + ms_free(from); + + counters = get_stats(lc); + switch (new_call_state) { + case LinphoneCallOutgoingInit :counters->number_of_LinphoneTransferCallOutgoingInit++;break; + case LinphoneCallOutgoingProgress :counters->number_of_LinphoneTransferCallOutgoingProgress++;break; + case LinphoneCallOutgoingRinging :counters->number_of_LinphoneTransferCallOutgoingRinging++;break; + case LinphoneCallOutgoingEarlyMedia :counters->number_of_LinphoneTransferCallOutgoingEarlyMedia++;break; + case LinphoneCallConnected :counters->number_of_LinphoneTransferCallConnected++;break; + case LinphoneCallStreamsRunning :counters->number_of_LinphoneTransferCallStreamsRunning++;break; + case LinphoneCallError :counters->number_of_LinphoneTransferCallError++;break; + default: + CU_FAIL("unexpected event");break; + } +} + +#ifdef VIDEO_ENABLED +static void linphone_call_cb(LinphoneCall *call,void * user_data) { + char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); + char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); + stats* counters; + LinphoneCore* lc=(LinphoneCore*)user_data; + ms_message("call from [%s] to [%s] receive iFrame",from,to); + ms_free(to); + ms_free(from); + counters = (stats*)get_stats(lc); + counters->number_of_IframeDecoded++; +} +#endif + +static void check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee) { + LinphoneCall *c1,*c2; + int i; + int dummy=0; + + c1=linphone_core_get_current_call(caller->lc); + c2=linphone_core_get_current_call(callee->lc); + + for (i=0; i<24 /*=12s need at least one exchange of SR to maybe 10s*/; i++) { + if (linphone_call_get_audio_stats(c1)->round_trip_delay >0.0 + && linphone_call_get_audio_stats(c2)->round_trip_delay >0.0 + && (!linphone_call_log_video_enabled(linphone_call_get_call_log(c1)) || linphone_call_get_video_stats(c1)->round_trip_delay>0.0) + && (!linphone_call_log_video_enabled(linphone_call_get_call_log(c2)) || linphone_call_get_video_stats(c2)->round_trip_delay>0.0)) { + break; + + } + wait_for_until(caller->lc,callee->lc,&dummy,1,500); /*just to sleep while iterating*/ + + } + CU_ASSERT_TRUE(linphone_call_get_audio_stats(c1)->round_trip_delay>0.0); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(c2)->round_trip_delay>0.0); + if (linphone_call_log_video_enabled(linphone_call_get_call_log(c1))) { + CU_ASSERT_TRUE(linphone_call_get_video_stats(c1)->round_trip_delay>0.0); + } + if (linphone_call_log_video_enabled(linphone_call_get_call_log(c2))) { + CU_ASSERT_TRUE(linphone_call_get_video_stats(c2)->round_trip_delay>0.0); + } + +} + +bool_t call_with_params(LinphoneCoreManager* caller_mgr + ,LinphoneCoreManager* callee_mgr + , const LinphoneCallParams *caller_params + , const LinphoneCallParams *callee_params) { + int retry=0; + stats initial_caller=caller_mgr->stat; + stats initial_callee=callee_mgr->stat; + bool_t result=FALSE; + char hellopath[256]; + /*use playfile for callee to avoid locking on capture card*/ + linphone_core_use_files (callee_mgr->lc,TRUE); + snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); + linphone_core_set_play_file(callee_mgr->lc,hellopath); + if (!caller_params){ + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address(caller_mgr->lc,callee_mgr->identity)); + }else{ + CU_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(caller_mgr->lc,callee_mgr->identity,caller_params)); + } + + /*linphone_core_invite(caller_mgr->lc,"pauline");*/ + + CU_ASSERT_TRUE(wait_for(callee_mgr->lc + ,caller_mgr->lc + ,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived + ,initial_callee.number_of_LinphoneCallIncomingReceived+1)); + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); + CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,initial_caller.number_of_LinphoneCallOutgoingProgress+1); + + + while (caller_mgr->stat.number_of_LinphoneCallOutgoingRinging!=(initial_caller.number_of_LinphoneCallOutgoingRinging + 1) + && caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia!=(initial_caller.number_of_LinphoneCallOutgoingEarlyMedia +1) + && retry++ <20) { + linphone_core_iterate(caller_mgr->lc); + linphone_core_iterate(callee_mgr->lc); + ms_usleep(100000); + } + + + CU_ASSERT_TRUE((caller_mgr->stat.number_of_LinphoneCallOutgoingRinging==initial_caller.number_of_LinphoneCallOutgoingRinging+1) + |(caller_mgr->stat.number_of_LinphoneCallOutgoingEarlyMedia==initial_caller.number_of_LinphoneCallOutgoingEarlyMedia+1)); + + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(callee_mgr->lc)); + if (!linphone_core_get_current_call_remote_address(callee_mgr->lc)) + return 0; + else { + LinphoneAddress* callee_from=linphone_address_clone(caller_mgr->identity); + linphone_address_set_port(callee_from,0); /*remove port because port is never present in from header*/ + if (linphone_call_params_get_privacy(linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc))) == LinphonePrivacyNone) { + CU_ASSERT_TRUE(linphone_address_weak_equal(callee_from,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + } else { + CU_ASSERT_FALSE(linphone_address_weak_equal(callee_from,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + } + linphone_address_destroy(callee_from); + } + if (callee_params) + linphone_core_accept_call_with_params(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc),callee_params); + else + linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); + + CU_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); + CU_ASSERT_TRUE(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,initial_callee.number_of_LinphoneCallConnected+1)); + /*just to sleep*/ + result = wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_caller.number_of_LinphoneCallStreamsRunning+1) + && + wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,initial_callee.number_of_LinphoneCallStreamsRunning+1); + + if (linphone_core_get_media_encryption(caller_mgr->lc) + && linphone_core_get_media_encryption(callee_mgr->lc)) { + const LinphoneCallParams* call_param = linphone_call_get_current_params(linphone_core_get_current_call(callee_mgr->lc)); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc)); + call_param = linphone_call_get_current_params(linphone_core_get_current_call(caller_mgr->lc)); + CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(caller_mgr->lc)); + } + return result; +} +bool_t call_with_caller_params(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr, const LinphoneCallParams *params) { + return call_with_params(caller_mgr,callee_mgr,params,NULL); +} + +bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr){ + return call_with_params(caller_mgr,callee_mgr,NULL,NULL); +} + +static void simple_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + check_rtcp(marie,pauline); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void simple_call_compatibility_mode(void) { + char route[256]; + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + LinphoneCore* lc_marie=marie->lc; + LinphoneCore* lc_pauline=pauline->lc; + stats* stat_marie=&marie->stat; + stats* stat_pauline=&pauline->stat; + LinphoneProxyConfig* proxy; + LinphoneAddress* identity; + LinphoneAddress* proxy_address; + char*tmp; + LCSipTransports transport; + + linphone_core_get_default_proxy(lc_marie,&proxy); + CU_ASSERT_PTR_NOT_NULL (proxy); + identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + + + proxy_address=linphone_address_new(linphone_proxy_config_get_addr(proxy)); + linphone_address_clean(proxy_address); + tmp=linphone_address_as_string_uri_only(proxy_address); + linphone_proxy_config_set_server_addr(proxy,tmp); + sprintf(route,"sip:%s",test_route); + linphone_proxy_config_set_route(proxy,route); + ms_free(tmp); + linphone_address_destroy(proxy_address); + linphone_core_get_sip_transports(lc_marie,&transport); + transport.udp_port=0; + transport.tls_port=0; + transport.dtls_port=0; + /*only keep tcp*/ + linphone_core_set_sip_transports(lc_marie,&transport); + stat_marie->number_of_LinphoneRegistrationOk=0; + + CU_ASSERT_TRUE (wait_for(lc_marie,lc_marie,&stat_marie->number_of_LinphoneRegistrationOk,1)); + + linphone_core_invite(lc_marie,"pauline"); + + CU_ASSERT_TRUE (wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(lc_pauline)); + CU_ASSERT_EQUAL(stat_marie->number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallOutgoingRinging,1)); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call_remote_address(lc_pauline)); + if (linphone_core_get_current_call_remote_address(lc_pauline)) { + CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(lc_pauline))); + linphone_address_destroy(identity); + + linphone_core_accept_call(lc_pauline,linphone_core_get_current_call(lc_pauline)); + + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallStreamsRunning,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,1)); + /*just to sleep*/ + wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallStreamsRunning,3); + linphone_core_terminate_all_calls(lc_pauline); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_pauline->number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(lc_pauline,lc_marie,&stat_marie->number_of_LinphoneCallEnd,1)); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + +static void cancelled_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + //CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonCanceled); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void disable_all_codecs_except_one(LinphoneCore *lc, const char *mime){ + const MSList *elem=linphone_core_get_audio_codecs(lc); + PayloadType *pt; + + for(;elem!=NULL;elem=elem->next){ + pt=(PayloadType*)elem->data; + linphone_core_enable_payload_type(lc,pt,FALSE); + } + pt=linphone_core_find_payload_type(lc,mime,-1,-1); + CU_ASSERT_PTR_NOT_NULL_FATAL(pt); + linphone_core_enable_payload_type(lc,pt,TRUE); +} + +static void call_failed_because_of_codecs(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* out_call; + + disable_all_codecs_except_one(marie->lc,"pcmu"); + disable_all_codecs_except_one(pauline->lc,"pcma"); + out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + + /*flexisip will retain the 415 until the "urgent reply" timeout arrives.*/ + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,6000)); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonMedia); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived,0); + + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_dns_time_out(void) { + LinphoneCoreManager* marie = linphone_core_manager_new2( "empty_rc", FALSE); + LCSipTransports transport = {9773,0,0,0}; + int i; + + linphone_core_set_sip_transports(marie->lc,&transport); + linphone_core_iterate(marie->lc); + sal_set_dns_timeout(marie->lc->sal,0); + linphone_core_invite(marie->lc,"sip:toto@toto.com"); + for(i=0;i<10;i++){ + ms_usleep(200000); + linphone_core_iterate(marie->lc); + } + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallReleased,1); + linphone_core_manager_destroy(marie); +} + +static void early_cancelled_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new2( "empty_rc",FALSE); + + LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); + linphone_core_terminate_call(pauline->lc,out_call); + + /*since everything is executed in a row, no response can be received from the server, thus the CANCEL cannot be sent. + It will ring at Marie's side.*/ + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + /* now the CANCEL should have been sent and the the call at marie's side should terminate*/ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void cancelled_ringing_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + LinphoneCall* out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + + linphone_core_terminate_call(pauline->lc,out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void early_declined_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCallLog* out_call_log; + LinphoneCall* out_call; + + linphone_core_set_max_calls(marie->lc,0); + out_call = linphone_core_invite(pauline->lc,"marie"); + linphone_call_ref(out_call); + + /*wait until flexisip transfers the busy...*/ + CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,33000)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallError,1); + /* FIXME http://git.linphone.org/mantis/view.php?id=757 + + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonBusy); + */ + if (ms_list_size(linphone_core_get_call_logs(pauline->lc))>0) { + CU_ASSERT_PTR_NOT_NULL(out_call_log=(LinphoneCallLog*)(linphone_core_get_call_logs(pauline->lc)->data)); + CU_ASSERT_EQUAL(linphone_call_log_get_status(out_call_log),LinphoneCallAborted); + } + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_declined(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + LinphoneCall* in_call; + LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); + linphone_call_ref(out_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_PTR_NOT_NULL(in_call=linphone_core_get_current_call(marie->lc)); + if (in_call) { + linphone_call_ref(in_call); + linphone_core_terminate_call(marie->lc,in_call); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); + CU_ASSERT_EQUAL(linphone_call_get_reason(in_call),LinphoneReasonDeclined); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonDeclined); + linphone_call_unref(in_call); + } + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_terminated_by_caller(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_no_sdp(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_no_sdp_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(marie,pauline)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state) { + LinphoneCall *c1,*c2; + bool_t success=FALSE; + int i; + + c1=linphone_core_get_current_call(caller->lc); + c2=linphone_core_get_current_call(callee->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + for (i=0;i<200;i++){ + if ((c1 != NULL) && (c2 != NULL)) { + if (linphone_call_get_audio_stats(c1)->ice_state==LinphoneIceStateHostConnection && + linphone_call_get_audio_stats(c2)->ice_state==LinphoneIceStateHostConnection ){ + success=TRUE; + break; + } + linphone_core_iterate(caller->lc); + linphone_core_iterate(callee->lc); + } + ms_usleep(50000); + } + return success; +} + +static void call_with_ice(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + /*wait for the ICE reINVITE to complete*/ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + check_rtcp(marie,pauline); + + + /*then close the call*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_custom_headers(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall *c1,*c2; + LinphoneCallParams *params; + const LinphoneCallParams *remote_params; + const char *hvalue; + char* tmp=linphone_address_as_string_uri_only(marie->identity); + char tmp2[256]; + snprintf(tmp2,sizeof(tmp2),"%s?uriHeader=myUriHeader",tmp); + LinphoneAddress* marie_identity=linphone_address_new(tmp2); + ms_free(tmp); + linphone_address_destroy(marie->identity); + marie->identity=marie_identity; + + params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_add_custom_header(params,"Weather","bad"); + linphone_call_params_add_custom_header(params,"Working","yes"); + + CU_ASSERT_TRUE(call_with_caller_params(pauline,marie,params)); + linphone_call_params_destroy(params); + + c1=linphone_core_get_current_call(marie->lc); + c2=linphone_core_get_current_call(pauline->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + remote_params=linphone_call_get_remote_params(c1); + hvalue=linphone_call_params_get_custom_header(remote_params,"Weather"); + CU_ASSERT_PTR_NOT_NULL(hvalue); + CU_ASSERT_STRING_EQUAL(hvalue,"bad"); + hvalue=linphone_call_params_get_custom_header(remote_params,"uriHeader"); + CU_ASSERT_PTR_NOT_NULL(hvalue); + CU_ASSERT_STRING_EQUAL(hvalue,"myUriHeader"); + + CU_ASSERT_PTR_NOT_NULL(linphone_call_get_remote_contact(c1)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_paused_resumed(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_obj; + + CU_ASSERT_TRUE(call(pauline,marie)); + call_obj = linphone_core_get_current_call(pauline->lc); + + linphone_core_pause_call(pauline->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + + linphone_core_resume_call(pauline->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static bool_t pause_call_1(LinphoneCoreManager* mgr_1,LinphoneCall* call_1,LinphoneCoreManager* mgr_2,LinphoneCall* call_2) { + stats initial_call_stat_1=mgr_1->stat; + stats initial_call_stat_2=mgr_2->stat; + linphone_core_pause_call(mgr_1->lc,call_1); + CU_ASSERT_TRUE(wait_for(mgr_1->lc,mgr_2->lc,&mgr_1->stat.number_of_LinphoneCallPausing,initial_call_stat_1.number_of_LinphoneCallPausing+1)); + CU_ASSERT_TRUE(wait_for(mgr_1->lc,mgr_2->lc,&mgr_1->stat.number_of_LinphoneCallPaused,initial_call_stat_1.number_of_LinphoneCallPaused+1)); + CU_ASSERT_TRUE(wait_for(mgr_1->lc,mgr_2->lc,&mgr_2->stat.number_of_LinphoneCallPausedByRemote,initial_call_stat_2.number_of_LinphoneCallPausedByRemote+1)); + CU_ASSERT_EQUAL(linphone_call_get_state(call_1),LinphoneCallPaused); + CU_ASSERT_EQUAL(linphone_call_get_state(call_2),LinphoneCallPausedByRemote); + return linphone_call_get_state(call_1) == LinphoneCallPaused && linphone_call_get_state(call_2)==LinphoneCallPausedByRemote; +} + +static void call_paused_resumed_from_callee(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_obj; + + CU_ASSERT_TRUE(call(pauline,marie)); + call_obj = linphone_core_get_current_call(marie->lc); + + linphone_core_pause_call(marie->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + + linphone_core_resume_call(marie->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + +#ifdef VIDEO_ENABLED +static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee) { + LinphoneVideoPolicy caller_policy; + LinphoneCallParams* callee_params; + LinphoneCall* call_obj; + caller_policy.automatically_accept=TRUE; + caller_policy.automatically_initiate=TRUE; + linphone_core_enable_video_capture(callee->lc, TRUE); + linphone_core_enable_video_display(callee->lc, TRUE); + linphone_core_enable_video_capture(caller->lc, TRUE); + linphone_core_enable_video_display(caller->lc, FALSE); + linphone_core_set_video_policy(caller->lc,&caller_policy); + stats initial_caller_stat=caller->stat; + stats initial_callee_stat=callee->stat; + + call_obj = linphone_core_get_current_call(callee->lc); + callee_params = linphone_call_params_copy(linphone_call_get_current_params(call_obj)); + /*add video*/ + linphone_call_params_enable_video(callee_params,TRUE); + linphone_core_update_call(callee->lc,call_obj,callee_params); + + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallUpdatedByRemote,initial_caller_stat.number_of_LinphoneCallUpdatedByRemote+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallUpdating,initial_callee_stat.number_of_LinphoneCallUpdating+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&callee->stat.number_of_LinphoneCallStreamsRunning,initial_callee_stat.number_of_LinphoneCallStreamsRunning+1)); + CU_ASSERT_TRUE(wait_for(caller->lc,callee->lc,&caller->stat.number_of_LinphoneCallStreamsRunning,initial_caller_stat.number_of_LinphoneCallStreamsRunning+1)); + + CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(callee->lc)))); + CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(linphone_core_get_current_call(caller->lc)))); + + linphone_call_set_next_video_frame_decoded_callback(call_obj,linphone_call_cb,callee->lc); + /*send vfu*/ + linphone_call_send_vfu_request(call_obj); + return wait_for(caller->lc,callee->lc,&callee->stat.number_of_IframeDecoded,initial_callee_stat.number_of_IframeDecoded+1); + +} +static void call_with_video_added(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_TRUE(add_video(pauline,marie)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + + +static void call_with_declined_video(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCallParams* callee_params; + LinphoneCallParams* caller_params; + LinphoneCall* marie_call; + LinphoneCall* pauline_call; + + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, TRUE); + linphone_core_enable_video_capture(pauline->lc, TRUE); + linphone_core_enable_video_display(pauline->lc, FALSE); + + caller_params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(caller_params,TRUE); + callee_params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_enable_video(callee_params,FALSE); + CU_ASSERT_TRUE(call_with_params(pauline,marie,caller_params,callee_params)); + marie_call=linphone_core_get_current_call(marie->lc); + pauline_call=linphone_core_get_current_call(pauline->lc); + + CU_ASSERT_FALSE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); + CU_ASSERT_FALSE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call))); + + + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCallParams* callee_params; + LinphoneCallParams* caller_params; + LinphoneCall* marie_call; + LinphoneCall* pauline_call; + + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, TRUE); + linphone_core_enable_video_capture(pauline->lc, TRUE); + linphone_core_enable_video_display(pauline->lc, FALSE); + + caller_params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(caller_params,TRUE); + callee_params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_enable_video(callee_params,TRUE); + CU_ASSERT_TRUE(call_with_params(pauline,marie,caller_params,callee_params)); + marie_call=linphone_core_get_current_call(marie->lc); + pauline_call=linphone_core_get_current_call(pauline->lc); + + CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); + CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(pauline_call))); + + /*check video path*/ + linphone_call_set_next_video_frame_decoded_callback(marie_call,linphone_call_cb,marie->lc); + linphone_call_send_vfu_request(marie_call); + CU_ASSERT_TRUE( wait_for(marie->lc,pauline->lc,&marie->stat.number_of_IframeDecoded,1)); + + check_rtcp(marie,pauline); + + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +#endif /*VIDEO_ENABLED*/ + +static void call_with_media_relay(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + CU_ASSERT_TRUE(call(pauline,marie)); + check_rtcp(pauline,marie); + +#ifdef VIDEO_ENABLED + CU_ASSERT_TRUE(add_video(pauline,marie)); + check_rtcp(pauline,marie); +#endif + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + +} + +static void call_with_privacy(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall *c1,*c2; + LinphoneCallParams *params; + LinphoneProxyConfig* pauline_proxy; + params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_set_privacy(params,LinphonePrivacyId); + + CU_ASSERT_TRUE(call_with_caller_params(pauline,marie,params)); + linphone_call_params_destroy(params); + + c1=linphone_core_get_current_call(pauline->lc); + c2=linphone_core_get_current_call(marie->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + /*make sure local identity is unchanged*/ + CU_ASSERT_TRUE(linphone_address_weak_equal(linphone_call_log_get_from(linphone_call_get_call_log(c1)),pauline->identity)); + + /*make sure remote identity is hidden*/ + CU_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + + CU_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + /*test proxy config privacy*/ + linphone_core_get_default_proxy(pauline->lc,&pauline_proxy); + linphone_proxy_config_set_privacy(pauline_proxy,LinphonePrivacyId); + + CU_ASSERT_TRUE(call(pauline,marie)); + c1=linphone_core_get_current_call(pauline->lc); + c2=linphone_core_get_current_call(marie->lc); + + CU_ASSERT_PTR_NOT_NULL(c1); + CU_ASSERT_PTR_NOT_NULL(c2); + + /*make sure remote identity is hidden*/ + CU_ASSERT_FALSE(linphone_address_weak_equal(linphone_call_get_remote_address(c2),pauline->identity)); + + CU_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(c2)),LinphonePrivacyId); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,2)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + + + +static void simple_conference(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + stats initial_marie_stat; + stats initial_pauline_stat; + stats initial_laure_stat; + + LinphoneCall* marie_call_pauline; + LinphoneCall* pauline_called_by_marie; + LinphoneCall* marie_call_laure; + + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + CU_ASSERT_TRUE(call(marie,pauline)); + marie_call_pauline=linphone_core_get_current_call(marie->lc); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + CU_ASSERT_TRUE(pause_call_1(marie,marie_call_pauline,pauline,pauline_called_by_marie)); + + CU_ASSERT_TRUE(call(marie,laure)); + initial_marie_stat=marie->stat; + initial_pauline_stat=pauline->stat; + initial_laure_stat=laure->stat; + + marie_call_laure=linphone_core_get_current_call(marie->lc); + + CU_ASSERT_PTR_NOT_NULL_FATAL(marie_call_laure); + linphone_core_add_to_conference(marie->lc,marie_call_laure); + CU_ASSERT_TRUE(wait_for(marie->lc,laure->lc,&marie->stat.number_of_LinphoneCallUpdating,initial_marie_stat.number_of_LinphoneCallUpdating+1)); + + + + linphone_core_add_to_conference(marie->lc,marie_call_pauline); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallResuming,initial_marie_stat.number_of_LinphoneCallResuming+1,2000)); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,initial_pauline_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,initial_laure_stat.number_of_LinphoneCallStreamsRunning+1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,initial_marie_stat.number_of_LinphoneCallStreamsRunning+2,3000)); + + CU_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); + CU_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3) + + linphone_core_terminate_conference(marie->lc); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} + + +static void srtp_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),LinphoneMediaEncryptionSRTP); + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),LinphoneMediaEncryptionSRTP); + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } else { + ms_warning ("not tested because srtp not available"); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void call_with_declined_srtp(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + CU_ASSERT_TRUE(call(pauline,marie)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } else { + ms_warning ("not tested because srtp not available"); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +#ifdef VIDEO_ENABLED +static void srtp_video_ice_call(void) { + int i=0; +#else +static void srtp_ice_call(void) { +#endif + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + if (linphone_core_media_encryption_supported(marie->lc,LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); + + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); +#ifdef VIDEO_ENABLED + for (i=0;i<100;i++) { /*fixme to workaround a crash*/ + ms_usleep(20000); + linphone_core_iterate(marie->lc); + linphone_core_iterate(pauline->lc); + } + + add_video(pauline,marie); + + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + check_rtcp(marie,pauline); + /*wait for ice to found the direct path*/ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); +#endif + + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } else { + ms_warning ("not tested because srtp not available"); + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + +static void early_media_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1); + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void early_media_call_forking(void) { + LinphoneCoreManager* marie1 = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc"); + MSList *lcs=NULL; + LinphoneCallParams *params=linphone_core_create_default_call_parameters(pauline->lc); + LinphoneVideoPolicy pol; + LinphoneCall *marie1_call; + LinphoneCall *marie2_call; + LinphoneCall *pauline_call; + int dummy=0; + char ringbackpath[256]; + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); + + pol.automatically_accept=1; + pol.automatically_initiate=1; + + linphone_core_set_user_agent(marie1->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(marie2->lc,"Natted Linphone",NULL); + linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); + + linphone_core_enable_video(pauline->lc,TRUE,TRUE); + + linphone_core_enable_video(marie1->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie1->lc,&pol); + /*use playfile for marie1 to avoid locking on capture card*/ + linphone_core_use_files (marie1->lc,TRUE); + linphone_core_set_play_file(marie1->lc,ringbackpath); + + + linphone_core_enable_video(marie2->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie2->lc,&pol); + linphone_core_set_audio_port_range(marie2->lc,40200,40300); + linphone_core_set_video_port_range(marie2->lc,40400,40500); + /*use playfile for marie2 to avoid locking on capture card*/ + linphone_core_use_files (marie2->lc,TRUE); + linphone_core_set_play_file(marie2->lc,ringbackpath); + + + lcs=ms_list_append(lcs,marie1->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,pauline->lc); + + linphone_call_params_enable_early_media_sending(params,TRUE); + linphone_call_params_enable_video(params,TRUE); + + linphone_core_invite_address_with_params(pauline->lc,marie1->identity,params); + linphone_call_params_destroy(params); + + CU_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,1000)); + + pauline_call=linphone_core_get_current_call(pauline->lc); + marie1_call=linphone_core_get_current_call(marie1->lc); + marie2_call=linphone_core_get_current_call(marie2->lc); + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,3000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>70); + + linphone_core_accept_call(marie1->lc,linphone_core_get_current_call(marie1->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,1000)); + + /*marie2 should get her call terminated*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,1000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); + + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,1000)); + + ms_list_free(lcs); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); +} + +static void simple_call_transfer(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + LinphoneCall* pauline_called_by_marie; + LinphoneCall *marie_calling_pauline; + LinphoneCall *marie_calling_laure; + + char* laure_identity=linphone_address_as_string(laure->identity); + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + + CU_ASSERT_TRUE(call(marie,pauline)); + marie_calling_pauline=linphone_core_get_current_call(marie->lc); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + reset_counters(&laure->stat); + + + linphone_core_transfer_call(pauline->lc,pauline_called_by_marie,laure_identity); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallRefered,1,2000)); + /*marie pausing pauline*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPausing,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausedByRemote,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPaused,1,2000)); + /*marie calling laure*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + + CU_ASSERT_PTR_NOT_NULL(linphone_call_get_transfer_target_call(marie_calling_pauline)); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingProgress,1,2000)); + linphone_core_accept_call(laure->lc,linphone_core_get_current_call(laure->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + + marie_calling_laure=linphone_core_get_current_call(marie->lc); + CU_ASSERT_PTR_NOT_NULL_FATAL(marie_calling_laure); + CU_ASSERT_TRUE(linphone_call_get_transferer_call(marie_calling_laure)==marie_calling_pauline); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallConnected,1,2000)); + + /*terminate marie to pauline call*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,2000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} + +static void unattended_call_transfer(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + LinphoneCall* pauline_called_by_marie; + + char* laure_identity=linphone_address_as_string(laure->identity); + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + + CU_ASSERT_TRUE(call(marie,pauline)); + pauline_called_by_marie=linphone_core_get_current_call(marie->lc); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + reset_counters(&laure->stat); + + linphone_core_transfer_call(marie->lc,pauline_called_by_marie,laure_identity); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + + /*marie ends the call */ + linphone_core_terminate_call(marie->lc,pauline_called_by_marie); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + + /*Pauline starts the transfer*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); + linphone_core_accept_call(laure->lc,linphone_core_get_current_call(laure->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} + +static void unattended_call_transfer_with_error(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* pauline_called_by_marie; + + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + + CU_ASSERT_TRUE(call(marie,pauline)); + pauline_called_by_marie=linphone_core_get_current_call(marie->lc); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + + linphone_core_transfer_call(marie->lc,pauline_called_by_marie,"unknown_user"); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + + /*Pauline starts the transfer*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); + /* and immediately get an error*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,2000)); + + /*the error must be reported back to marie*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallError,1,2000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_list_free(lcs); +} + + +static void call_transfer_existing_call_outgoing_call(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + + LinphoneCall* marie_call_pauline; + LinphoneCall* pauline_called_by_marie; + LinphoneCall* marie_call_laure; + LinphoneCall* laure_called_by_marie; + LinphoneCall* lcall; + + MSList* lcs=ms_list_append(NULL,marie->lc); + const MSList* calls; + lcs=ms_list_append(lcs,pauline->lc); + lcs=ms_list_append(lcs,laure->lc); + + /*marie call pauline*/ + CU_ASSERT_TRUE(call(marie,pauline)); + marie_call_pauline=linphone_core_get_current_call(marie->lc); + pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); + /*marie pause pauline*/ + CU_ASSERT_TRUE(pause_call_1(marie,marie_call_pauline,pauline,pauline_called_by_marie)); + + /*marie call laure*/ + CU_ASSERT_TRUE(call(marie,laure)); + marie_call_laure=linphone_core_get_current_call(marie->lc); + laure_called_by_marie=linphone_core_get_current_call(laure->lc); + /*marie pause pauline*/ + CU_ASSERT_TRUE(pause_call_1(marie,marie_call_laure,laure,laure_called_by_marie)); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + reset_counters(&laure->stat); + + + linphone_core_transfer_call_to_another(marie->lc,marie_call_pauline,marie_call_laure); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); + + /*pauline pausing marie*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPausing,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallPaused,1,2000)); + /*pauline calling laure*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallOutgoingProgress,1,2000)); + + /*laure accept call*/ + for(calls=linphone_core_get_calls(laure->lc);calls!=NULL;calls=calls->next) { + lcall = (LinphoneCall*)calls->data; + if (linphone_call_get_state(lcall) == LinphoneCallIncomingReceived) { + CU_ASSERT_EQUAL(linphone_call_get_replaced_call(lcall),laure_called_by_marie); + linphone_core_accept_call(laure->lc,lcall); + break; + } + } + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallConnected,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallConnected,1,2000)); + + /*terminate marie to pauline/laure call*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,2,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); + ms_list_free(lcs); +} + +static void check_call_state(LinphoneCoreManager* mgr,LinphoneCallState state) { + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(mgr->lc)); + if (linphone_core_get_current_call(mgr->lc)) + CU_ASSERT_EQUAL(linphone_call_get_state(linphone_core_get_current_call(mgr->lc)),state); +} +static void call_established_with_rejected_info(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + int dummy=0; + + CU_ASSERT_TRUE(call(pauline,marie)); + + sal_enable_unconditional_answer(marie->lc->sal,TRUE); + linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),linphone_core_create_info_message(pauline->lc)); + + wait_for_until(marie->lc,pauline->lc,&dummy,1,1000); /*just to sleep while iterating 1s*/ + + sal_enable_unconditional_answer(marie->lc->sal,FALSE); + + linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),linphone_core_create_info_message(pauline->lc)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_inforeceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_inforeceived,1); + + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + +static void call_established_with_rejected_reinvite(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + + + linphone_core_update_call( pauline->lc + ,linphone_core_get_current_call(pauline->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); + + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonNotAcceptable); + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallStreamsRunning,1); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_established_with_rejected_reinvite_with_error(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*add PCMA*/ + + + sal_enable_unconditional_answer(marie->lc->sal,TRUE); + + linphone_core_update_call( pauline->lc + ,linphone_core_get_current_call(pauline->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); + + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + CU_ASSERT_EQUAL(linphone_call_get_reason(linphone_core_get_current_call(pauline->lc)),LinphoneReasonNone); /*might be change later*/ + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallStreamsRunning,1); + check_call_state(pauline,LinphoneCallStreamsRunning); + check_call_state(marie,LinphoneCallStreamsRunning); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +#ifdef VIDEO_ENABLED +#endif + +test_t call_tests[] = { + { "Early declined call", early_declined_call }, + { "Call declined", call_declined }, + { "Cancelled call", cancelled_call }, + { "Early cancelled call", early_cancelled_call}, + { "Call with DNS timeout", call_with_dns_time_out }, + { "Cancelled ringing call", cancelled_ringing_call }, + { "Call failed because of codecs", call_failed_because_of_codecs }, + { "Simple call", simple_call }, + { "Call with media relay", call_with_media_relay}, + { "Simple call compatibility mode", simple_call_compatibility_mode }, + { "Early-media call", early_media_call }, + { "Early-media call forking", early_media_call_forking }, + { "Call terminated by caller", call_terminated_by_caller }, + { "Call without SDP", call_with_no_sdp}, + { "Call paused resumed", call_paused_resumed }, + { "Call paused resumed from callee", call_paused_resumed_from_callee }, + { "SRTP call", srtp_call }, + { "SRTP call with declined srtp", call_with_declined_srtp }, +#ifdef VIDEO_ENABLED + { "Simple video call",video_call}, + { "SRTP ice video call", srtp_video_ice_call }, + { "Call with video added", call_with_video_added }, + { "Call with video declined",call_with_declined_video}, +#else + { "SRTP ice call", srtp_ice_call }, +#endif + { "Call with privacy", call_with_privacy }, + { "Simple conference", simple_conference }, + { "Simple call transfer", simple_call_transfer }, + { "Unattended call transfer", unattended_call_transfer }, + { "Unattended call transfer with error", unattended_call_transfer_with_error }, + { "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }, + { "Call with ICE", call_with_ice }, + { "Call with custom headers",call_with_custom_headers}, + { "Call established with rejected INFO",call_established_with_rejected_info}, + { "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite}, + { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error} +}; + +test_suite_t call_test_suite = { + "Call", + NULL, + NULL, + sizeof(call_tests) / sizeof(call_tests[0]), + call_tests +}; + diff --git a/tester/certificates/altname/agent.pem b/tester/certificates/altname/agent.pem new file mode 100644 index 000000000..c75085728 --- /dev/null +++ b/tester/certificates/altname/agent.pem @@ -0,0 +1,76 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDHZG78iwkkxJeq3ZPuQwY9DfdcNCvHXayW+5p5VUULV50ohJKt +JJzhp5ysq4VH7q/dmOnMnbYTACnqVSlph88zRdQJd/g0h6T4DyWa5Jxe+R1hwLWV +fgeSXstCK8m9SwxKqnqA5mPZxfARXg3r4XWkUK2A1lWIXCkZU3MMD4JJ4QIDAQAB +AoGAGgyi+1dmwGj2r5n3I5+aBwv2DxO5zHgOfkMssUFUneC6ZXq8duZboJd3Po/B +/93NGBRMJzFLgjv5PeYWXPUjOoJT7eg0aDJKX/uMKSvzhyIL/bUJPfyo2GCmkAr5 +CF5EBFFjlsui2kSFusxbQmyzZkkIl3OYdlTBdQFsmEROk8kCQQD3aW1ZPbDkSxsi +09VZBWVW95LojcxYQeqjPTs8EAB2jKmR4aw8KGKCz+yBGwiSdukDZ/p3IftuifHk +J+3a6kqnAkEAzlBKjM8xVWprTp/3p1DMYNA+KNsXuf08xGB/zegpU561FjUzK7U4 +QKyDSIaRgSv4WAJbIauwaZdydM6Q0DnANwJBAKEQGQeHiaiU3E2H6dPSF27OLO0H +ooeyIbWzHuSy5hpG5/z4FM/02myePzCtEJ+ImZiGEB+OF8iWNMp60/U3oPECQAoR +RPIGEkQ2wzG9AJq7iJ2Yy8+2kTvULajvhI0JrSqVbgS9Z9fUKgCN6oIZfvQsrxus +UcIc3KjqaP1mLw7aIpUCQH5S0B+GOwKa8+RbuRcgBvksqkRwRZn6jawoNJJSBCDn +gQJ5B9PvJXppTsbnulSD2srhUqCR1pzGfnl8bYV8b8Q= +-----END RSA PRIVATE KEY----- + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 5 (0x5) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Some-State, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=Jehan Monnier/emailAddress=jehan.monnier@belledonne-communications.com + Validity + Not Before: Sep 23 15:58:58 2013 GMT + Not After : Sep 23 15:58:58 2014 GMT + Subject: C=FR, ST=France, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=See altname for DNS name/emailAddress=jehan.monnier@belledonne-communications.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:c7:64:6e:fc:8b:09:24:c4:97:aa:dd:93:ee:43: + 06:3d:0d:f7:5c:34:2b:c7:5d:ac:96:fb:9a:79:55: + 45:0b:57:9d:28:84:92:ad:24:9c:e1:a7:9c:ac:ab: + 85:47:ee:af:dd:98:e9:cc:9d:b6:13:00:29:ea:55: + 29:69:87:cf:33:45:d4:09:77:f8:34:87:a4:f8:0f: + 25:9a:e4:9c:5e:f9:1d:61:c0:b5:95:7e:07:92:5e: + cb:42:2b:c9:bd:4b:0c:4a:aa:7a:80:e6:63:d9:c5: + f0:11:5e:0d:eb:e1:75:a4:50:ad:80:d6:55:88:5c: + 29:19:53:73:0c:0f:82:49:e1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Subject Alternative Name: + DNS:altname.linphone.org, DNS:*.wildcard2.linphone.org + Signature Algorithm: sha1WithRSAEncryption + 21:05:d3:36:82:5d:f4:f4:70:71:17:ac:06:12:49:0c:d6:c3: + 21:07:9c:2f:79:c8:14:da:e5:3a:92:04:22:5b:74:cf:53:3c: + 95:33:51:93:66:04:59:c6:3d:dd:22:cf:3f:f8:0e:24:93:6b: + 2a:02:f7:bf:ba:89:1b:72:9a:d4:1b:bf:22:3d:08:51:13:a4: + bf:43:d2:89:a1:c5:f2:e3:04:24:1e:d4:33:64:06:83:2d:b6: + 66:34:16:a9:f4:8d:6f:3f:71:86:ab:73:19:36:ae:43:29:7e: + 9d:6c:35:3a:75:f4:22:8b:c5:e3:1e:ee:c1:0d:d7:63:cc:95: + 4a:6a +-----BEGIN CERTIFICATE----- +MIIDSjCCArOgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK +DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV +BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwOTIzMTU1ODU4WhcN +MTQwOTIzMTU1ODU4WjCBwjELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTER +MA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNh +dGlvbnMxDDAKBgNVBAsMA0xBQjEhMB8GA1UEAwwYU2VlIGFsdG5hbWUgZm9yIERO +UyBuYW1lMTowOAYJKoZIhvcNAQkBFitqZWhhbi5tb25uaWVyQGJlbGxlZG9ubmUt +Y29tbXVuaWNhdGlvbnMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH +ZG78iwkkxJeq3ZPuQwY9DfdcNCvHXayW+5p5VUULV50ohJKtJJzhp5ysq4VH7q/d +mOnMnbYTACnqVSlph88zRdQJd/g0h6T4DyWa5Jxe+R1hwLWVfgeSXstCK8m9SwxK +qnqA5mPZxfARXg3r4XWkUK2A1lWIXCkZU3MMD4JJ4QIDAQABo1UwUzAJBgNVHRME +AjAAMAsGA1UdDwQEAwIF4DA5BgNVHREEMjAwghRhbHRuYW1lLmxpbnBob25lLm9y +Z4IYKi53aWxkY2FyZDIubGlucGhvbmUub3JnMA0GCSqGSIb3DQEBBQUAA4GBACEF +0zaCXfT0cHEXrAYSSQzWwyEHnC95yBTa5TqSBCJbdM9TPJUzUZNmBFnGPd0izz/4 +DiSTayoC97+6iRtymtQbvyI9CFETpL9D0omhxfLjBCQe1DNkBoMttmY0Fqn0jW8/ +cYarcxk2rkMpfp1sNTp19CKLxeMe7sEN12PMlUpq +-----END CERTIFICATE----- diff --git a/tester/certificates/altname/cafile.pem b/tester/certificates/altname/cafile.pem new file mode 100644 index 000000000..2fd957d39 --- /dev/null +++ b/tester/certificates/altname/cafile.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDRjCCAq+gAwIBAgIJAJ3nFcA7qFrOMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD +VQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwIR3Jlbm9ibGUx +IjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNhdGlvbnMxDDAKBgNVBAsMA0xB +QjEWMBQGA1UEAwwNSmVoYW4gTW9ubmllcjE6MDgGCSqGSIb3DQEJARYramVoYW4u +bW9ubmllckBiZWxsZWRvbm5lLWNvbW11bmljYXRpb25zLmNvbTAeFw0xMzA0MzAx +MzMwMThaFw0yMzA0MjgxMzMwMThaMIG7MQswCQYDVQQGEwJGUjETMBEGA1UECAwK +U29tZS1TdGF0ZTERMA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9u +bmUgQ29tbXVuaWNhdGlvbnMxDDAKBgNVBAsMA0xBQjEWMBQGA1UEAwwNSmVoYW4g +TW9ubmllcjE6MDgGCSqGSIb3DQEJARYramVoYW4ubW9ubmllckBiZWxsZWRvbm5l +LWNvbW11bmljYXRpb25zLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +z5F8mMh3SUr6NUd7tq2uW2Kdn22Zn3kNpLYb78AQK4IoQMOLGXbBdyoXvz1fublg +bxtLYsiGhICd7Ul9zLGc3edn85LbD3Skb7ERx6MakRnYep3FzagZJhn14QEaZCx6 +3Qs0Ir4rSP7hmlpYt8VO/zqqNR3tsA59O0D9c7bpQ7UCAwEAAaNQME4wHQYDVR0O +BBYEFAZfXccWr2L4LW5xA4ig1h0rBH+6MB8GA1UdIwQYMBaAFAZfXccWr2L4LW5x +A4ig1h0rBH+6MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAKvmt2m1o +axGKc0DjiJPypU/NsAf4Yu0nOnY8pHqJJCB0AWVoAPM7vGYPWpeH7LSdGZLuT9eK +FUWGJhPnkrnklmBdVB0l7qXYjR5uf766HDkoDxuLhNifow3IYvsS+L2Y6puRQb9w +HLMDE29mBDl0WyoX3h0yR0EiAO15V9A7I10= +-----END CERTIFICATE----- diff --git a/tester/certificates/altname/openssl-altname.cnf b/tester/certificates/altname/openssl-altname.cnf new file mode 100644 index 000000000..c4edb6c7d --- /dev/null +++ b/tester/certificates/altname/openssl-altname.cnf @@ -0,0 +1,359 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + + req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = FR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = France + +localityName = Locality Name (eg, city) +localityName_default = Grenoble + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Belledonne Communications + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = LAB +#organizationalUnitName_default = + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_max = 64 +commonName_default = See altname for DNS name + +emailAddress = Email Address +emailAddress_max = 64 +emailAddress_default = jehan.monnier@belledonne-communications.com + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = @alt_names + +[alt_names] +DNS.1 = altname.linphone.org +DNS.2 = *.wildcard2.linphone.org + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) + +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = md5, sha1 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) diff --git a/tester/certificates/cn/agent.pem b/tester/certificates/cn/agent.pem new file mode 100644 index 000000000..978221639 --- /dev/null +++ b/tester/certificates/cn/agent.pem @@ -0,0 +1,80 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDHZG78iwkkxJeq3ZPuQwY9DfdcNCvHXayW+5p5VUULV50ohJKt +JJzhp5ysq4VH7q/dmOnMnbYTACnqVSlph88zRdQJd/g0h6T4DyWa5Jxe+R1hwLWV +fgeSXstCK8m9SwxKqnqA5mPZxfARXg3r4XWkUK2A1lWIXCkZU3MMD4JJ4QIDAQAB +AoGAGgyi+1dmwGj2r5n3I5+aBwv2DxO5zHgOfkMssUFUneC6ZXq8duZboJd3Po/B +/93NGBRMJzFLgjv5PeYWXPUjOoJT7eg0aDJKX/uMKSvzhyIL/bUJPfyo2GCmkAr5 +CF5EBFFjlsui2kSFusxbQmyzZkkIl3OYdlTBdQFsmEROk8kCQQD3aW1ZPbDkSxsi +09VZBWVW95LojcxYQeqjPTs8EAB2jKmR4aw8KGKCz+yBGwiSdukDZ/p3IftuifHk +J+3a6kqnAkEAzlBKjM8xVWprTp/3p1DMYNA+KNsXuf08xGB/zegpU561FjUzK7U4 +QKyDSIaRgSv4WAJbIauwaZdydM6Q0DnANwJBAKEQGQeHiaiU3E2H6dPSF27OLO0H +ooeyIbWzHuSy5hpG5/z4FM/02myePzCtEJ+ImZiGEB+OF8iWNMp60/U3oPECQAoR +RPIGEkQ2wzG9AJq7iJ2Yy8+2kTvULajvhI0JrSqVbgS9Z9fUKgCN6oIZfvQsrxus +UcIc3KjqaP1mLw7aIpUCQH5S0B+GOwKa8+RbuRcgBvksqkRwRZn6jawoNJJSBCDn +gQJ5B9PvJXppTsbnulSD2srhUqCR1pzGfnl8bYV8b8Q= +-----END RSA PRIVATE KEY----- + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6 (0x6) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Some-State, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=Jehan Monnier/emailAddress=jehan.monnier@belledonne-communications.com + Validity + Not Before: Sep 23 16:13:11 2013 GMT + Not After : Sep 21 16:13:11 2023 GMT + Subject: C=FR, ST=France, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=sip2.linphone.org, CN=*.wildcard1.linphone.org/emailAddress=jehan.monnier@belledonne-communications.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:c7:64:6e:fc:8b:09:24:c4:97:aa:dd:93:ee:43: + 06:3d:0d:f7:5c:34:2b:c7:5d:ac:96:fb:9a:79:55: + 45:0b:57:9d:28:84:92:ad:24:9c:e1:a7:9c:ac:ab: + 85:47:ee:af:dd:98:e9:cc:9d:b6:13:00:29:ea:55: + 29:69:87:cf:33:45:d4:09:77:f8:34:87:a4:f8:0f: + 25:9a:e4:9c:5e:f9:1d:61:c0:b5:95:7e:07:92:5e: + cb:42:2b:c9:bd:4b:0c:4a:aa:7a:80:e6:63:d9:c5: + f0:11:5e:0d:eb:e1:75:a4:50:ad:80:d6:55:88:5c: + 29:19:53:73:0c:0f:82:49:e1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 32:19:16:F0:DD:2C:34:8F:FE:12:5D:4F:E0:0C:EE:C5:06:C8:B1:8C + X509v3 Authority Key Identifier: + keyid:06:5F:5D:C7:16:AF:62:F8:2D:6E:71:03:88:A0:D6:1D:2B:04:7F:BA + + Signature Algorithm: sha1WithRSAEncryption + af:2e:d2:9a:b9:e0:ca:c8:e3:25:eb:30:0b:5e:02:e9:43:2d: + 84:09:11:d1:be:8e:a4:86:bf:c7:19:aa:18:c3:55:b2:07:c5: + 68:ff:c6:39:f7:2b:da:27:85:34:8b:7b:6c:92:8f:ba:aa:9d: + 44:f3:0c:47:88:7a:0c:b1:e0:c7:6f:eb:af:d2:ab:d0:6d:25: + d5:ff:40:37:69:2b:bd:f2:6e:4a:42:32:29:98:27:c7:ec:34: + 25:eb:22:6f:83:50:82:1c:08:88:77:ec:31:82:c2:0c:77:b1: + 2b:c9:7d:6c:ff:95:d0:10:cf:8e:9f:2e:eb:a1:a6:40:fc:c0: + ec:83 +-----BEGIN CERTIFICATE----- +MIIDjDCCAvWgAwIBAgIBBjANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK +DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV +BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMwOTIzMTYxMzExWhcN +MjMwOTIxMTYxMzExWjCB3jELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTER +MA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNh +dGlvbnMxDDAKBgNVBAsMA0xBQjEaMBgGA1UEAwwRc2lwMi5saW5waG9uZS5vcmcx +ITAfBgNVBAMMGCoud2lsZGNhcmQxLmxpbnBob25lLm9yZzE6MDgGCSqGSIb3DQEJ +ARYramVoYW4ubW9ubmllckBiZWxsZWRvbm5lLWNvbW11bmljYXRpb25zLmNvbTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAx2Ru/IsJJMSXqt2T7kMGPQ33XDQr +x12slvuaeVVFC1edKISSrSSc4aecrKuFR+6v3ZjpzJ22EwAp6lUpaYfPM0XUCXf4 +NIek+A8lmuScXvkdYcC1lX4Hkl7LQivJvUsMSqp6gOZj2cXwEV4N6+F1pFCtgNZV +iFwpGVNzDA+CSeECAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYd +T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFDIZFvDdLDSP +/hJdT+AM7sUGyLGMMB8GA1UdIwQYMBaAFAZfXccWr2L4LW5xA4ig1h0rBH+6MA0G +CSqGSIb3DQEBBQUAA4GBAK8u0pq54MrI4yXrMAteAulDLYQJEdG+jqSGv8cZqhjD +VbIHxWj/xjn3K9onhTSLe2ySj7qqnUTzDEeIegyx4Mdv66/Sq9BtJdX/QDdpK73y +bkpCMimYJ8fsNCXrIm+DUIIcCIh37DGCwgx3sSvJfWz/ldAQz46fLuuhpkD8wOyD +-----END CERTIFICATE----- diff --git a/tester/certificates/cn/cafile.pem b/tester/certificates/cn/cafile.pem new file mode 100644 index 000000000..2fd957d39 --- /dev/null +++ b/tester/certificates/cn/cafile.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDRjCCAq+gAwIBAgIJAJ3nFcA7qFrOMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD +VQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwIR3Jlbm9ibGUx +IjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNhdGlvbnMxDDAKBgNVBAsMA0xB +QjEWMBQGA1UEAwwNSmVoYW4gTW9ubmllcjE6MDgGCSqGSIb3DQEJARYramVoYW4u +bW9ubmllckBiZWxsZWRvbm5lLWNvbW11bmljYXRpb25zLmNvbTAeFw0xMzA0MzAx +MzMwMThaFw0yMzA0MjgxMzMwMThaMIG7MQswCQYDVQQGEwJGUjETMBEGA1UECAwK +U29tZS1TdGF0ZTERMA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9u +bmUgQ29tbXVuaWNhdGlvbnMxDDAKBgNVBAsMA0xBQjEWMBQGA1UEAwwNSmVoYW4g +TW9ubmllcjE6MDgGCSqGSIb3DQEJARYramVoYW4ubW9ubmllckBiZWxsZWRvbm5l +LWNvbW11bmljYXRpb25zLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +z5F8mMh3SUr6NUd7tq2uW2Kdn22Zn3kNpLYb78AQK4IoQMOLGXbBdyoXvz1fublg +bxtLYsiGhICd7Ul9zLGc3edn85LbD3Skb7ERx6MakRnYep3FzagZJhn14QEaZCx6 +3Qs0Ir4rSP7hmlpYt8VO/zqqNR3tsA59O0D9c7bpQ7UCAwEAAaNQME4wHQYDVR0O +BBYEFAZfXccWr2L4LW5xA4ig1h0rBH+6MB8GA1UdIwQYMBaAFAZfXccWr2L4LW5x +A4ig1h0rBH+6MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAKvmt2m1o +axGKc0DjiJPypU/NsAf4Yu0nOnY8pHqJJCB0AWVoAPM7vGYPWpeH7LSdGZLuT9eK +FUWGJhPnkrnklmBdVB0l7qXYjR5uf766HDkoDxuLhNifow3IYvsS+L2Y6puRQb9w +HLMDE29mBDl0WyoX3h0yR0EiAO15V9A7I10= +-----END CERTIFICATE----- diff --git a/tester/certificates/cn/openssl-cn.cnf b/tester/certificates/cn/openssl-cn.cnf new file mode 100644 index 000000000..c6262db31 --- /dev/null +++ b/tester/certificates/cn/openssl-cn.cnf @@ -0,0 +1,357 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = FR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = France + +localityName = Locality Name (eg, city) +localityName_default = Grenoble + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Belledonne Communications + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = LAB +#organizationalUnitName_default = + +0.commonName = Common Name (e.g. server FQDN or YOUR name) +0.commonName_max = 64 +0.commonName_default = sip2.linphone.org + +1.commonName = Common Name (e.g. server FQDN or YOUR name) +1.commonName_max = 64 +1.commonName_default = *.wildcard1.linphone.org + +emailAddress = Email Address +emailAddress_max = 64 +emailAddress_default = jehan.monnier@belledonne-communications.com + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) + +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = md5, sha1 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) diff --git a/tester/empty_rc b/tester/empty_rc new file mode 100644 index 000000000..2fa8c43a3 --- /dev/null +++ b/tester/empty_rc @@ -0,0 +1,6 @@ +[net] +mtu=1300 + +[sip] +ping_with_options=0 +sip_random_port=1 \ No newline at end of file diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c new file mode 100644 index 000000000..811bad527 --- /dev/null +++ b/tester/eventapi_tester.c @@ -0,0 +1,249 @@ +/* + belle-sip - SIP (RFC3261) library. + 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 3 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, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "lpconfig.h" +#include +#include "liblinphone_tester.h" + + +static const char *subscribe_content="blabla"; +static const char *notify_content="blabla"; + +void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content){ + CU_ASSERT_PTR_NOT_NULL_FATAL(content); + CU_ASSERT_TRUE(strcmp(notify_content,(const char*)content->data)==0); + LinphoneCoreManager *mgr=get_manager(lc); + mgr->stat.number_of_NotifyReceived++; +} + +void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) { + stats* counters = get_stats(lc); + LinphoneCoreManager *mgr=get_manager(lc); + LinphoneContent content={0}; + + content.type="application"; + content.subtype="somexml2"; + content.data=(void*)notify_content; + content.size=strlen(notify_content); + + switch(state){ + case LinphoneSubscriptionNone: + break; + case LinphoneSubscriptionIncomingReceived: + counters->number_of_LinphoneSubscriptionIncomingReceived++; + if (!mgr->decline_subscribe) + linphone_event_accept_subscription(lev); + else + linphone_event_deny_subscription(lev, LinphoneReasonDeclined); + break; + case LinphoneSubscriptionOutoingInit: + counters->number_of_LinphoneSubscriptionOutgoingInit++; + break; + case LinphoneSubscriptionPending: + counters->number_of_LinphoneSubscriptionPending++; + break; + case LinphoneSubscriptionActive: + counters->number_of_LinphoneSubscriptionActive++; + if (linphone_event_get_subscription_dir(lev)==LinphoneSubscriptionIncoming){ + mgr->lev=lev; + linphone_event_notify(lev,&content); + } + break; + case LinphoneSubscriptionTerminated: + counters->number_of_LinphoneSubscriptionTerminated++; + mgr->lev=NULL; + break; + case LinphoneSubscriptionError: + counters->number_of_LinphoneSubscriptionError++; + mgr->lev=NULL; + break; + } +} + +void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state){ + stats* counters = get_stats(lc); + switch(state){ + case LinphonePublishProgress: counters->number_of_LinphonePublishProgress++; break; + case LinphonePublishOk: counters->number_of_LinphonePublishOk++; break; + case LinphonePublishError: counters->number_of_LinphonePublishError++; break; + case LinphonePublishExpiring: counters->number_of_LinphonePublishExpiring++; break; + case LinphonePublishCleared: counters->number_of_LinphonePublishCleared++;break; + default: + break; + } + +} + +static void subscribe_test_declined(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneContent content={0}; + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + + + content.type="application"; + content.subtype="somexml"; + content.data=(char*)subscribe_content; + content.size=strlen(subscribe_content); + + pauline->decline_subscribe=TRUE; + + linphone_core_subscribe(marie->lc,pauline->identity,"dodo",600,&content); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionError,1,21000));/*yes flexisip may wait 20 secs in case of forking*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + +static void subscribe_test_with_args(bool_t terminated_by_subscriber, bool_t test_refreshing) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneContent content={0}; + LinphoneEvent *lev; + int expires= test_refreshing ? 4 : 600; + MSList* lcs=ms_list_append(NULL,marie->lc); + + + lcs=ms_list_append(lcs,pauline->lc); + + + content.type="application"; + content.subtype="somexml"; + content.data=(char*)subscribe_content; + content.size=strlen(subscribe_content); + + lev=linphone_core_subscribe(marie->lc,pauline->identity,"dodo",expires,&content); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionOutgoingInit,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionIncomingReceived,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionActive,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionActive,1,1000)); + + /*make sure marie receives first notification before terminating*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_NotifyReceived,1,1000)); + + if (test_refreshing){ + wait_for_list(lcs,NULL,0,6000); + CU_ASSERT_TRUE(linphone_event_get_subscription_state(pauline->lev)==LinphoneSubscriptionActive); + } + + if (terminated_by_subscriber){ + linphone_event_terminate(lev); + }else{ + CU_ASSERT_PTR_NOT_NULL_FATAL(pauline->lev); + linphone_event_terminate(pauline->lev); + } + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneSubscriptionTerminated,1,1000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void subscribe_test_terminated_by_subscriber(void){ + subscribe_test_with_args(TRUE,FALSE); +} + +static void subscribe_test_terminated_by_notifier(void){ + subscribe_test_with_args(FALSE,FALSE); +} + +/* Caution: this test does not really check that the subscribe are refreshed, because the core is not managing the expiration of + * unrefreshed subscribe dialogs. So it is just checking that it is not crashing. + */ +static void subscribe_test_refreshed(void){ + subscribe_test_with_args(TRUE,TRUE); +} + +static void publish_test_with_args(bool_t refresh){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneContent content={0}; + LinphoneEvent *lev; + MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(lcs,pauline->lc); + + + content.type="application"; + content.subtype="somexml"; + content.data=(char*)subscribe_content; + content.size=strlen(subscribe_content); + + lp_config_set_int(marie->lc->config,"sip","refresh_generic_publish",!refresh); + + lev=linphone_core_publish(marie->lc,pauline->identity,"dodo",5,&content); + linphone_event_ref(lev); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,1000)); + + if (!refresh){ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishExpiring,1,5000)); + linphone_event_update_publish(lev,&content); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishProgress,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishOk,1,1000)); + }else{ + + } + + linphone_event_terminate(lev); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphonePublishCleared,1,1000)); + + linphone_event_unref(lev); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void publish_test(){ + publish_test_with_args(TRUE); +} + +static void publish_no_auto_test(){ + publish_test_with_args(FALSE); +} + +test_t event_tests[] = { + { "Subscribe declined" , subscribe_test_declined }, + { "Subscribe terminated by subscriber", subscribe_test_terminated_by_subscriber }, + { "Subscribe refreshed", subscribe_test_refreshed }, + { "Subscribe terminated by notifier", subscribe_test_terminated_by_notifier }, + { "Publish", publish_test }, + { "Publish without automatic refresh",publish_no_auto_test } +}; + +test_suite_t event_test_suite = { + "Event", + NULL, + NULL, + sizeof(event_tests) / sizeof(event_tests[0]), + event_tests +}; + diff --git a/tester/flexisip.conf b/tester/flexisip.conf new file mode 100755 index 000000000..b4d39a5c0 --- /dev/null +++ b/tester/flexisip.conf @@ -0,0 +1,555 @@ +## +## This is the default Flexisip configuration file +## + +## +## Some global settings of the flexisip proxy. +## +[global] +# Outputs very detailed logs +# Default value: false +debug=1 + +# Automatically respawn flexisip in case of abnormal termination +# (crashes) +# Default value: true +auto-respawn=true + +# List of white space separated host names pointing to this machine. +# This is to prevent loops while routing SIP messages. +# Default value: localhost +aliases=localhost sipopen.example.org sip.example.org auth.example.org auth1.example.org auth2.example.org client.example.org + +# List of white space separated SIP uris where the proxy must listen.Wildcard +# (*) can be used to mean 'all local ip addresses'. If 'transport' +# prameter is unspecified, it will listen to both udp and tcp. An +# local address to bind can be indicated in the 'maddr' parameter, +# while the domain part of the uris are used as public domain or +# ip address. Here some examples to understand: +# * listen on all local interfaces for udp and tcp, on standart +# port: +# transports=sip:* +# * listen on all local interfaces for udp,tcp and tls, on standart +# ports: +# transports=sip:* sips:* +# * listen on 192.168.0.29:6060 with tls, but public hostname is +# 'sip.linphone.org' used in SIP messages. Bind address won't appear: +# transports=sips:sip.linphone.org:6060;maddr=192.168.0.29 +# Default value: sip:* +#transports=sip:192.168.56.101:5060 sips:192.168.56.101:5061 +transports=sip:*:5060 sips:*:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:*:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:*:5063;require-peer-certificate=1 +# An absolute path of a directory where TLS server certificate and +# private key can be found, concatenated inside an 'agent.pem' file. +# Default value: /etc/flexisip/tls +tls-certificates-dir=/etc/flexisip/tls/certificates/cn +#tls-certificates-dir=/media/sf_workspaces/workspace-macosx/flexisip + +## +## STUN server parameters. +## +[stun-server] +# Enable or disable stun server. +# Default value: true +enabled=true + +# Local ip address where to bind the socket. +# Default value: 0.0.0.0 +bind-address=0.0.0.0 + +# STUN server port number. +# Default value: 3478 +port=3478 + +## +## DOS protection parameters. +## +[dos-protection] +# Enable or disable DOS protection using IPTables firewall. +# Default value: false +enabled=false + +# List of whitelist IPs which won't be affected by DOS protection. +# Default value: 127.0.0.1 +authorized-ip=127.0.0.1 + +# Local ports to protect. +# Default value: 5060 +port=5060 + +# Time (in seconds) while an IP have to not send any packet in order +# to leave the blacklist. +# Default value: 60 +ban-duration=60 + +# Number of packets authorized in 1sec before considering them as +# DOS attack. +# Default value: 20 +packets-limit=20 + +# Maximal amount of simultaneous connections to accept. +# Default value: 1000 +maximum-connections=1000 + +## +## The NatHelper module executes small tasks to make SIP work smoothly +## despite firewalls.It corrects the Contact headers that contain +## obviously inconsistent addresses, and adds a Record-Route to ensure +## subsequent requests are routed also by the proxy, through the +## UDP or TCP channel each client opened to the proxy. +## +[module::NatHelper] +# Indicate whether the module is activated. +# Default value: true +enabled=true + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# Internal URI parameter added to response contact by first proxy +# and cleaned by last one. +# Default value: verified +contact-verified-param=verified + +## +## The authentication module challenges SIP requests according to +## a user/password database. +## +[module::Authentication] +# Indicate whether the module is activated. +# Default value: false +enabled=true + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= from.uri.domain contains 'sip.example.org' || from.uri.domain contains 'auth.example.org' || from.uri.domain contains 'auth1.example.org' || from.uri.domain contains 'auth2.example.org' + +# List of whitespace separated domain names to challenge. Others +# are denied. +# Default value: +auth-domains= sip.example.org auth.example.org auth1.example.org auth2.example.org + +client-certificates-domains=client.example.org + + +# List of whitespace separated IP which will not be challenged. +# Default value: +trusted-hosts= + +# Database backend implementation [odbc, file]. +# Default value: odbc +db-implementation=file + +# Odbc connection string to use for connecting to database. ex1: +# DSN=myodbc3; where 'myodbc3' is the datasource name. ex2: DRIVER={MySQL};SERVER=host;DATABASE=db;USER=user;PASSWORD=pass;OPTION=3; +# for a DSN-less connection. ex3: /etc/flexisip/passwd; for a file +# containing one 'user@domain password' by line. +# Default value: +datasource=/etc/flexisip/userdb.conf + +# Odbc SQL request to execute to obtain the password +# . Named parameters are :id (the user found in the from header), +# :domain (the authorization realm) and :authid (the authorization +# username). The use of the :id parameter is mandatory. +# Default value: select password from accounts where id = :id and domain = :domain and authid=:authid +request=select password from accounts where id = :id and domain = :domain and authid=:authid + +# Maximum length of the login column in database. +# Default value: 100 +max-id-length=100 + +# Maximum length of the password column in database +# Default value: 100 +max-password-length=100 + +# Use pooling in odbc +# Default value: true +odbc-pooling=true + +# Display timing statistics after this count of seconds +# Default value: 0 +odbc-display-timings-interval=0 + +# Display timing statistics once the number of samples reach this +# number. +# Default value: 0 +odbc-display-timings-after-count=0 + +# Retrieve passwords asynchronously. +# Default value: false +odbc-asynchronous=false + +# Duration of the validity of the credentials added to the cache +# in seconds. +# Default value: 1800 +cache-expire=1800 + +# Retrieve password immediately so that it is cached when an authenticated +# request arrives. +# Default value: true +immediate-retrieve-password=true + +# True if retrieved passwords from the database are hashed. HA1=MD5(A1) +# = MD5(username:realm:pass). +# Default value: false +hashed-passwords=false + +# When receiving a proxy authenticate challenge, generate a new +# challenge for this proxy. +# Default value: false +new-auth-on-407=false + +## +## ... +## +[module::GatewayAdapter] +# Indicate whether the module is activated. +# Default value: false +enabled=false + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# A gateway uri where to send all requests, as a SIP url (eg 'sip:gateway.example.net') +# Default value: +gateway= + +# Modify the from and to domains of incoming register +# Default value: +gateway-domain= + +# The gateway will be added to the incoming register contacts. +# Default value: true +fork-to-gateway=true + +# Send a REGISTER to the gateway using this server as a contact +# in order to be notified on incoming calls by the gateway. +# Default value: true +register-on-gateway=true + +# Parameter name hosting the incoming domain that will be sent in +# the register to the gateway. +# Default value: routing-domain +routing-param=routing-domain + +[module::Router] + +# Store and retrieve contacts without using the domain. +# Default value: false +use-global-domain=false + +# Fork messages to all registered devices +# Default value: true +fork=true + +# Force forking and thus the creation of an outgoing transaction +# even when only one contact found +# Default value: true +stateful=true + +# Fork invites to late registers +# Default value: false +fork-late=false + +# Only forward one response of forked invite to the caller +# Default value: true +fork-one-response=true + +# All the forked have to decline in order to decline the caller +# invite +# Default value: false +fork-no-global-decline=false + +# Maximum duration for delivering a message (text) +# Default value: 3600 +message-delivery-timeout=3600 +## +## The Registrar module accepts REGISTERs for domains it manages, +## and store the address of record in order to route other requests +## destinated to the client who registered. +## +[module::Registrar] +# Indicate whether the module is activated. +# Default value: true +enabled=true + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# List of whitelist separated domain names to be managed by the +# registrar. +# Default value: localhost +reg-domains=localhost sip.example.org sipopen.example.org auth1.example.org sip2.linphone.org + +# Maximum number of registered contacts of an address of record. +# Default value: 15 +max-contacts-by-aor=15 + +# List of contact uri parameters that can be used to identify a +# user's device. +# Default value: line +unique-id-parameters=line + +# Maximum expire time for a REGISTER, in seconds. +# Default value: 86400 +max-expires=86400 + +# Minimum expire time for a REGISTER, in seconds. +# Default value: 60 +min-expires=1 + +# File containing the static records to add to database at startup. +# Format: one 'sip_uri contact_header' by line. Example: +# , +# Default value: +static-records-file= + +# Timeout in seconds after which the static records file is re-read +# and the contacts updated. +# Default value: 600 +static-records-timeout=600 + +# Implementation used for storing address of records contact uris. +# [redis-async, redis-sync, internal] +# Default value: internal +db-implementation=internal + + + + + + + + +# Generate a contact from the TO header and route it to the above +# destination. [sip:host:port] +# Default value: +generated-contact-route= + +# Require presence of authorization header for specified realm. +# [Realm] +# Default value: +generated-contact-expected-realm= + +## +## This module performs push notifications +## +[module::PushNotification] +# Indicate whether the module is activated. +# Default value: false +enabled=false + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# Number of second to wait before sending a push notification to +# device(if <=0 then disabled) +# Default value: 5 +timeout=5 + +# Maximum number of notifications queued for each client +# Default value: 10 +max-queue-size=10 + +# Enable push notification for apple devices +# Default value: true +apple=true + +# Path to directory where to find Apple Push Notification service +# certificates. They should bear the appid of the application, suffixed +# by the release mode and .pem extension. For example: org.linphone.dev.pem +# org.linphone.prod.pem com.somephone.dev.pem etc... The files should +# be .pem format, and made of certificate followed by private key. +# Default value: /etc/flexisip/apn +apple-certificate-dir=/etc/flexisip/apn + +# Enable push notification for android devices +# Default value: true +google=true + +# List of couple projectId:ApiKey for each android project which +# support push notifications +# Default value: +google-projects-api-keys= + +## +## The purpose of the ContactRouteInserter module is to masquerade +## the contact header of incoming registers that are not handled +## locally (think about flexisip used as a SBC gateway) in such a +## way that it is then possible to route back outgoing invites to +## the original address. It is a kind of similar mechanism as Record-Route, +## but for REGISTER. +## +[module::ContactRouteInserter] +# Indicate whether the module is activated. +# Default value: true +enabled=false + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# Hack for workarounding Nortel CS2k gateways bug. +# Default value: false +masquerade-contacts-for-invites=false + +## +## This module performs load balancing between a set of configured +## destination proxies. +## +[module::LoadBalancer] +# Indicate whether the module is activated. +# Default value: false +enabled=false + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# Whitespace separated list of sip routes to balance the requests. +# Example: +# Default value: +routes= + +## +## The MediaRelay module masquerades SDP message so that all RTP +## and RTCP streams go through the proxy. The RTP and RTCP streams +## are then routed so that each client receives the stream of the +## other. MediaRelay makes sure that RTP is ALWAYS established, even +## with uncooperative firewalls. +## +[module::MediaRelay] +# Indicate whether the module is activated. +# Default value: true +enabled=true + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (:q +# Default value: +filter= (user-agent contains 'Natted Linphone') + +# SDP attribute set by the first proxy to forbid subsequent proxies +# to provide relay. +# Default value: nortpproxy +nortpproxy=nortpproxy + +# Set the RTP direction during early media state (duplex, forward) +# Default value: duplex +#early-media-rtp-dir=duplex + +# The minimal value of SDP port range +# Default value: 1024 +sdp-port-range-min=1024 + +# The maximal value of SDP port range +# Default value: 65535 +sdp-port-range-max=65535 + +# Enable I-frame only filtering for video H264 for clients annoucing +# a total bandwith below this value expressed in kbit/s. Use 0 to +# disable the feature +# Default value: 0 +#h264-filtering-bandwidth=0 + +# When above option is activated, keep one I frame over this number. +# Default value: 1 +#h264-iframe-decim=1 + +## +## The purpose of the Transcoder module is to transparently transcode +## from one audio codec to another to make the communication possible +## between clients that do not share the same set of supported codecs. +## Concretely it adds all missing codecs into the INVITEs it receives, +## and adds codecs matching the original INVITE into the 200Ok. Rtp +## ports and addresses are masqueraded so that the streams can be +## processed by the proxy. The transcoding job is done in the background +## by the mediastreamer2 library, as consequence the set of supported +## codecs is exactly the the same as the codec set supported by mediastreamer2, +## including the possible plugins you may installed to extend mediastreamer2. +## WARNING: this module can conflict with the MediaRelay module as +## both are changin the SDP. Make sure to configure them with different +## to-domains or from-domains filter if you want to enable both of +## them. +## +[module::Transcoder] +# Indicate whether the module is activated. +# Default value: false +enabled=false + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# Nominal size of RTP jitter buffer, in milliseconds. A value of +# 0 means no jitter buffer (packet processing). +# Default value: 0 +jb-nom-size=0 + +# Whitespace separated list of user-agent strings for which audio +# rate control is performed. +# Default value: +rc-user-agents= + +# Whitespace seprated list of audio codecs, in order of preference. +# Default value: speex/8000 amr/8000 iLBC/8000 gsm/8000 pcmu/8000 pcma/8000 +audio-codecs=speex/8000 amr/8000 iLBC/8000 gsm/8000 pcmu/8000 pcma/8000 + +# If true, retransmissions of INVITEs will be blocked. The purpose +# of this option is to limit bandwidth usage and server load on +# reliable networks. +# Default value: false +block-retransmissions=false + +## +## This module executes the basic routing task of SIP requests and +## pass them to the transport layer. It must always be enabled. +## +[module::Forward] +# Indicate whether the module is activated. +# Default value: true +enabled=true + +# A request/response enters module if the boolean filter evaluates +# to true. Ex: from.uri.domain contains 'sip.linphone.org', from.uri.domain +# in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') +# && (user-agent == 'Linphone v2') +# Default value: +filter= + +# A sip uri where to send all requests +# Default value: +route= + +# Rewrite request-uri's host and port according to above route +# Default value: false +rewrite-req-uri=false + diff --git a/tester/images/nowebcamCIF.jpg b/tester/images/nowebcamCIF.jpg new file mode 100644 index 000000000..2ab8bdc2a Binary files /dev/null and b/tester/images/nowebcamCIF.jpg differ diff --git a/tester/laure_rc b/tester/laure_rc new file mode 100644 index 000000000..54a682401 --- /dev/null +++ b/tester/laure_rc @@ -0,0 +1,41 @@ +[sip] +sip_port=5092 +sip_tcp_port=5092 +sip_tls_port=5093 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=laure +userid=laure +passwd=secret +realm="sip.example.org" + + +[proxy_0] +reg_proxy=sip.example.org +reg_identity=sip:laure@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + + +[rtp] +audio_rtp_port=9010 +video_rtp_port=9012 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c new file mode 100644 index 000000000..1df32f237 --- /dev/null +++ b/tester/liblinphone_tester.c @@ -0,0 +1,561 @@ +/* + belle-sip - SIP (RFC3261) library. + 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 3 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, see . +*/ +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" +#if HAVE_CU_CURSES +#include "CUnit/CUCurses.h" +#endif + +static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file); + +static test_suite_t **test_suite = NULL; +static int nb_test_suites = 0; + + +#if HAVE_CU_CURSES +static unsigned char curses = 0; +#endif + + + +const char* test_domain="sipopen.example.org"; +const char* auth_domain="sip.example.org"; +const char* test_username="liblinphone_tester"; +const char* test_password="secret"; +const char* test_route="sip2.linphone.org"; + +#if WINAPI_FAMILY_PHONE_APP +const char *liblinphone_tester_file_prefix="Assets"; +#else +const char *liblinphone_tester_file_prefix="."; +#endif + +const char *userhostsfile = "tester_hosts"; + +#ifdef ANDROID +extern void AndroidPrintf(FILE *stream, const char *fmt, ...); +#define fprintf(file, fmt, ...) AndroidPrintf(file, fmt, ##__VA_ARGS__) +#endif + + +LinphoneAddress * create_linphone_address(const char * domain) { + LinphoneAddress *addr = linphone_address_new(NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(addr); + linphone_address_set_username(addr,test_username); + CU_ASSERT_STRING_EQUAL(test_username,linphone_address_get_username(addr)); + if (!domain) domain= test_route; + linphone_address_set_domain(addr,domain); + CU_ASSERT_STRING_EQUAL(domain,linphone_address_get_domain(addr)); + linphone_address_set_display_name(addr, NULL); + linphone_address_set_display_name(addr, "Mr Tester"); + CU_ASSERT_STRING_EQUAL("Mr Tester",linphone_address_get_display_name(addr)); + return addr; +} + +void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { + stats* counters; + LinphoneAuthInfo *info; + ms_message("Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + counters = get_stats(lc); + counters->number_of_auth_info_requested++; + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,realm,domain); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + +} + + + +void reset_counters( stats* counters) { + memset(counters,0,sizeof(stats)); +} + +static LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file) { + LinphoneCore* lc; + char filepath[256]={0}; + char ringpath[256]={0}; + char ringbackpath[256]={0}; + char rootcapath[256]={0}; + char dnsuserhostspath[256]={0}; + char nowebcampath[256]={0}; + + if (path==NULL) path="."; + + if (file){ + sprintf(filepath, "%s/%s", path, file); + CU_ASSERT_TRUE_FATAL(ortp_file_exist(filepath)==0); + } + + lc = linphone_core_new(v_table,NULL,*filepath!='\0' ? filepath : NULL,NULL); + + sal_enable_test_features(lc->sal,TRUE); + snprintf(rootcapath, sizeof(rootcapath), "%s/certificates/cn/cafile.pem", path); + linphone_core_set_root_ca(lc,rootcapath); + + sprintf(dnsuserhostspath, "%s/%s", path, userhostsfile); + sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); + + snprintf(ringpath,sizeof(ringpath), "%s/sounds/oldphone.wav",path); + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/ringback.wav", path); + linphone_core_set_ring(lc, ringpath); + linphone_core_set_ringback(lc, ringbackpath); + + snprintf(nowebcampath, sizeof(nowebcampath), "%s/images/nowebcamCIF.jpg", path); + linphone_core_set_static_picture(lc,nowebcampath); + return lc; +} + + +bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout) { + MSList* lcs=NULL; + bool_t result; + if (lc_1) + lcs=ms_list_append(lcs,lc_1); + if (lc_2) + lcs=ms_list_append(lcs,lc_2); + result=wait_for_list(lcs,counter,value,timout); + ms_list_free(lcs); + return result; +} +bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { + return wait_for_until(lc_1, lc_2,counter,value,2000); +} +bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { + int retry=0; + MSList* iterator; + while ((counter==NULL || *counternext) { + linphone_core_iterate((LinphoneCore*)(iterator->data)); + } + ms_usleep(100000); + } + if(counter && *counternext) { + linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); + } + if((pt = linphone_core_find_payload_type(lc,type,rate,1))) { + linphone_core_enable_payload_type(lc,pt, enable); + } + ms_list_free(codecs); +} + +static void enable_codec(LinphoneCore* lc,const char* type,int rate) { + set_codec_enable(lc,type,rate,TRUE); +} +stats * get_stats(LinphoneCore *lc){ + LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc); + return &manager->stat; +} + +LinphoneCoreManager *get_manager(LinphoneCore *lc){ + LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc); + return manager; +} + +LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies) { + LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1); + LinphoneProxyConfig* proxy; + int proxy_count; + int retry=0; + + mgr->v_table.registration_state_changed=registration_state_changed; + mgr->v_table.auth_info_requested=auth_info_requested; + mgr->v_table.call_state_changed=call_state_changed; + mgr->v_table.text_received=text_message_received; + mgr->v_table.message_received=message_received; + mgr->v_table.new_subscription_requested=new_subscription_requested; + mgr->v_table.notify_presence_received=notify_presence_received; + mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; + mgr->v_table.info_received=info_message_received; + mgr->v_table.subscription_state_changed=linphone_subscription_state_change; + mgr->v_table.notify_received=linphone_notify_received; + mgr->v_table.publish_state_changed=linphone_publish_state_changed; + mgr->lc=configure_lc_from(&mgr->v_table, liblinphone_tester_file_prefix, rc_file); + linphone_core_set_user_data(mgr->lc,mgr); + reset_counters(&mgr->stat); + /*CU_ASSERT_EQUAL(ms_list_size(linphone_core_get_proxy_config_list(lc)),proxy_count);*/ + if (check_for_proxies && rc_file) /**/ + proxy_count=ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)); + else + proxy_count=0; + + while (mgr->stat.number_of_LinphoneRegistrationOk2?(proxy_count-2)*10:0))) { + linphone_core_iterate(mgr->lc); + ms_usleep(100000); + } + CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationOk,proxy_count); + enable_codec(mgr->lc,"PCMU",8000); + + linphone_core_get_default_proxy(mgr->lc,&proxy); + if (proxy) { + mgr->identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + linphone_address_clean(mgr->identity); + } + return mgr; +} + +LinphoneCoreManager* linphone_core_manager_new( const char* rc_file) { + return linphone_core_manager_new2(rc_file, TRUE); +} + +void linphone_core_manager_stop(LinphoneCoreManager *mgr){ + if (mgr->lc) { + linphone_core_destroy(mgr->lc); + mgr->lc=NULL; + } +} + +void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { + if (mgr->lc) linphone_core_destroy(mgr->lc); + if (mgr->identity) linphone_address_destroy(mgr->identity); + ms_free(mgr); +} + + +static void add_test_suite(test_suite_t *suite) { + if (test_suite == NULL) { + test_suite = (test_suite_t **)malloc(10 * sizeof(test_suite_t *)); + } + test_suite[nb_test_suites] = suite; + nb_test_suites++; + if ((nb_test_suites % 10) == 0) { + test_suite = (test_suite_t **)realloc(test_suite, (nb_test_suites + 10) * sizeof(test_suite_t *)); + } +} + +static int run_test_suite(test_suite_t *suite) { + int i; + + CU_pSuite pSuite = CU_add_suite(suite->name, suite->init_func, suite->cleanup_func); + + for (i = 0; i < suite->nb_tests; i++) { + if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) { + return CU_get_error(); + } + } + + return 0; +} + +static int test_suite_index(const char *suite_name) { + int i; + + for (i = 0; i < liblinphone_tester_nb_test_suites(); i++) { + if ((strcmp(suite_name, test_suite[i]->name) == 0) && (strlen(suite_name) == strlen(test_suite[i]->name))) { + return i; + } + } + + return -1; +} + +static int test_index(const char *suite_name, const char *test_name) { + int j,i; + + j = test_suite_index(suite_name); + if(j != -1) { + for (i = 0; i < test_suite[j]->nb_tests; i++) { + if ((strcmp(test_name, test_suite[j]->tests[i].name) == 0) && (strlen(test_name) == strlen(test_suite[j]->tests[i].name))) { + return i; + } + } + } + + return -1; +} + +int liblinphone_tester_nb_test_suites(void) { + return nb_test_suites; +} + +int liblinphone_tester_nb_tests(const char *suite_name) { + int i = test_suite_index(suite_name); + if (i < 0) return 0; + return test_suite[i]->nb_tests; +} + +const char * liblinphone_tester_test_suite_name(int suite_index) { + if (suite_index >= liblinphone_tester_nb_test_suites()) return NULL; + return test_suite[suite_index]->name; +} + +const char * liblinphone_tester_test_name(const char *suite_name, int test_index) { + int suite_index = test_suite_index(suite_name); + if ((suite_index < 0) || (suite_index >= liblinphone_tester_nb_test_suites())) return NULL; + if (test_index >= test_suite[suite_index]->nb_tests) return NULL; + return test_suite[suite_index]->tests[test_index].name; +} + +void liblinphone_tester_init(void) { + add_test_suite(&setup_test_suite); + add_test_suite(®ister_test_suite); + add_test_suite(&call_test_suite); + add_test_suite(&message_test_suite); + add_test_suite(&presence_test_suite); +#ifdef UPNP + add_test_suite(&upnp_test_suite); +#endif + add_test_suite(&event_test_suite); +} + +void liblinphone_tester_uninit(void) { + if (test_suite != NULL) { + free(test_suite); + test_suite = NULL; + nb_test_suites = 0; + } +} + +int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) { + int i; + int ret; + /* initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) + return CU_get_error(); + + for (i = 0; i < liblinphone_tester_nb_test_suites(); i++) { + run_test_suite(test_suite[i]); + } + + if (suite_name){ + CU_pSuite suite; + CU_basic_set_mode(CU_BRM_VERBOSE); + suite=CU_get_suite_by_name(suite_name, CU_get_registry()); + if (test_name) { + CU_pTest test=CU_get_test_by_name(test_name, suite); + CU_ErrorCode err= CU_basic_run_test(suite, test); + if (err != CUE_SUCCESS) ms_error("CU_basic_run_test error %d", err); + } else + CU_basic_run_suite(suite); + } else + { +#if HAVE_CU_CURSES + if (curses) { + /* Run tests using the CUnit curses interface */ + CU_curses_run_tests(); + } + else +#endif + { + /* Run all tests using the CUnit Basic interface */ + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + } + } + + ret=CU_get_number_of_tests_failed()!=0; + CU_cleanup_registry(); + return ret; +} + +#ifdef ANDROID +#include + +static const char* LogDomain = "liblinphone_tester"; + +void linphone_android_log_handler(int prio, const char *fmt, va_list args) { + char str[4096]; + char *current; + char *next; + + vsnprintf(str, sizeof(str) - 1, fmt, args); + str[sizeof(str) - 1] = '\0'; + if (strlen(str) < 512) { + __android_log_write(prio, LogDomain, str); + } else { + current = str; + while ((next = strchr(current, '\n')) != NULL) { + *next = '\0'; + __android_log_write(prio, LogDomain, current); + current = next + 1; + } + __android_log_write(prio, LogDomain, current); + } +} + +static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt, va_list args) { + int prio; + switch(lev){ + case ORTP_DEBUG: prio = ANDROID_LOG_DEBUG; break; + case ORTP_MESSAGE: prio = ANDROID_LOG_INFO; break; + case ORTP_WARNING: prio = ANDROID_LOG_WARN; break; + case ORTP_ERROR: prio = ANDROID_LOG_ERROR; break; + case ORTP_FATAL: prio = ANDROID_LOG_FATAL; break; + default: prio = ANDROID_LOG_DEFAULT; break; + } + linphone_android_log_handler(prio, fmt, args); +} +#endif + +void helper(const char *name) { + fprintf(stderr,"%s \t--help\n" + "\t\t\t--verbose\n" + "\t\t\t--silent\n" + "\t\t\t--list-suites\n" + "\t\t\t--list-tests \n" + "\t\t\t--config \n" + "\t\t\t--domain \n" + "\t\t\t--auth-domain \n" + "\t\t\t--suite \n" + "\t\t\t--test \n" +#if HAVE_CU_CURSES + "\t\t\t--curses\n" +#endif + , name); +} + +#define CHECK_ARG(argument, index, argc) \ + if(index >= argc) { \ + fprintf(stderr, "Missing argument for \"%s\"\n", argument); \ + return -1; \ + } \ + +#ifndef WINAPI_FAMILY_PHONE_APP +int main (int argc, char *argv[]) { + int i,j; + int ret; + const char *suite_name=NULL; + const char *test_name=NULL; + + liblinphone_tester_init(); + + for(i=1;i +#include +#define CALLBACK_BUFFER_SIZE 1024 +static JNIEnv *current_env = NULL; +static jobject current_obj = 0; + +void cunit_android_trace_handler(int level, const char *fmt, va_list args) { + char buffer[CALLBACK_BUFFER_SIZE]; + JNIEnv *env = current_env; + if(env == NULL) return; + vsnprintf(buffer, CALLBACK_BUFFER_SIZE, fmt, args); + jstring javaString = (*env)->NewStringUTF(env, buffer); + jint javaLevel = level; + jclass cls = (*env)->GetObjectClass(env, current_obj); + jmethodID method = (*env)->GetMethodID(env, cls, "printLog", "(ILjava/lang/String;)V"); + (*env)->CallVoidMethod(env, current_obj, method, javaLevel, javaString); + (*env)->DeleteLocalRef(env,javaString); +} + +JNIEXPORT + +JNIEXPORT jint JNICALL Java_org_linphone_tester_Tester_run(JNIEnv *env, jobject obj, jobjectArray stringArray) { + int i, ret; + int argc = (*env)->GetArrayLength(env, stringArray); + char **argv = (char**) malloc(sizeof(char*) * argc); + + for (i=0; iGetObjectArrayElement(env, stringArray, i); + const char *rawString = (const char *) (*env)->GetStringUTFChars(env, string, 0); + argv[i] = strdup(rawString); + (*env)->ReleaseStringUTFChars(env, string, rawString); + } + current_env = env; + current_obj = obj; + CU_set_trace_handler(cunit_android_trace_handler); + ret = main(argc, argv); + current_env = NULL; + CU_set_trace_handler(NULL); + for (i=0; i. +*/ + +#ifndef LIBLINPHONE_TESTER_H_ +#define LIBLINPHONE_TESTER_H_ + + + +#include "CUnit/Basic.h" +#include "linphonecore.h" + +typedef void (*test_function_t)(void); +typedef int (*test_suite_function_t)(const char *name); + +typedef struct { + const char *name; + test_function_t func; +} test_t; + +typedef struct { + const char *name; + CU_InitializeFunc init_func; + CU_CleanupFunc cleanup_func; + int nb_tests; + test_t *tests; +} test_suite_t; + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char *liblinphone_tester_file_prefix; +extern test_suite_t setup_test_suite; +extern test_suite_t register_test_suite; +extern test_suite_t call_test_suite; +extern test_suite_t message_test_suite; +extern test_suite_t presence_test_suite; +extern test_suite_t upnp_test_suite; +extern test_suite_t event_test_suite; + + +extern int liblinphone_tester_nb_test_suites(void); +extern int liblinphone_tester_nb_tests(const char *suite_name); +extern const char * liblinphone_tester_test_suite_name(int suite_index); +extern const char * liblinphone_tester_test_name(const char *suite_name, int test_index); +extern void liblinphone_tester_init(void); +extern void liblinphone_tester_uninit(void); +extern int liblinphone_tester_run_tests(const char *suite_name, const char *test_name); + + +#ifdef __cplusplus +}; +#endif + + +const char* test_domain; +const char* auth_domain; +const char* test_username; +const char* test_password; +const char* test_route; + + +typedef struct _stats { + int number_of_LinphoneRegistrationNone; + int number_of_LinphoneRegistrationProgress ; + int number_of_LinphoneRegistrationOk ; + int number_of_LinphoneRegistrationCleared ; + int number_of_LinphoneRegistrationFailed ; + int number_of_auth_info_requested ; + + + int number_of_LinphoneCallIncomingReceived; + int number_of_LinphoneCallOutgoingInit; + int number_of_LinphoneCallOutgoingProgress; + int number_of_LinphoneCallOutgoingRinging; + int number_of_LinphoneCallOutgoingEarlyMedia; + int number_of_LinphoneCallConnected; + int number_of_LinphoneCallStreamsRunning; + int number_of_LinphoneCallPausing; + int number_of_LinphoneCallPaused; + int number_of_LinphoneCallResuming; + int number_of_LinphoneCallRefered; + int number_of_LinphoneCallError; + int number_of_LinphoneCallEnd; + int number_of_LinphoneCallPausedByRemote; + int number_of_LinphoneCallUpdatedByRemote; + int number_of_LinphoneCallIncomingEarlyMedia; + int number_of_LinphoneCallUpdating; + int number_of_LinphoneCallReleased; + + int number_of_LinphoneTransferCallOutgoingInit; + int number_of_LinphoneTransferCallOutgoingProgress; + int number_of_LinphoneTransferCallOutgoingRinging; + int number_of_LinphoneTransferCallOutgoingEarlyMedia; + int number_of_LinphoneTransferCallConnected; + int number_of_LinphoneTransferCallStreamsRunning; + int number_of_LinphoneTransferCallError; + + int number_of_LinphoneMessageReceived; + int number_of_LinphoneMessageReceivedLegacy; + int number_of_LinphoneMessageExtBodyReceived; + int number_of_LinphoneMessageInProgress; + int number_of_LinphoneMessageDelivered; + int number_of_LinphoneMessageNotDelivered; + + + int number_of_IframeDecoded; + + int number_of_NewSubscriptionRequest; + int number_of_NotifyReceived; + int number_of_LinphonePresenceActivityOffline; + int number_of_LinphonePresenceActivityOnline; + int number_of_LinphonePresenceActivityAppointment; + int number_of_LinphonePresenceActivityAway; + int number_of_LinphonePresenceActivityBreakfast; + int number_of_LinphonePresenceActivityBusy; + int number_of_LinphonePresenceActivityDinner; + int number_of_LinphonePresenceActivityHoliday; + int number_of_LinphonePresenceActivityInTransit; + int number_of_LinphonePresenceActivityLookingForWork; + int number_of_LinphonePresenceActivityLunch; + int number_of_LinphonePresenceActivityMeal; + int number_of_LinphonePresenceActivityMeeting; + int number_of_LinphonePresenceActivityOnThePhone; + int number_of_LinphonePresenceActivityOther; + int number_of_LinphonePresenceActivityPerformance; + int number_of_LinphonePresenceActivityPermanentAbsence; + int number_of_LinphonePresenceActivityPlaying; + int number_of_LinphonePresenceActivityPresentation; + int number_of_LinphonePresenceActivityShopping; + int number_of_LinphonePresenceActivitySleeping; + int number_of_LinphonePresenceActivitySpectator; + int number_of_LinphonePresenceActivitySteering; + int number_of_LinphonePresenceActivityTravel; + int number_of_LinphonePresenceActivityTV; + int number_of_LinphonePresenceActivityUnknown; + int number_of_LinphonePresenceActivityVacation; + int number_of_LinphonePresenceActivityWorking; + int number_of_LinphonePresenceActivityWorship; + const LinphonePresenceModel *last_received_presence; + + int number_of_inforeceived; + LinphoneInfoMessage* last_received_info_message; + + int number_of_LinphoneSubscriptionIncomingReceived; + int number_of_LinphoneSubscriptionOutgoingInit; + int number_of_LinphoneSubscriptionPending; + int number_of_LinphoneSubscriptionActive; + int number_of_LinphoneSubscriptionTerminated; + int number_of_LinphoneSubscriptionError; + + int number_of_LinphonePublishProgress; + int number_of_LinphonePublishOk; + int number_of_LinphonePublishExpiring; + int number_of_LinphonePublishError; + int number_of_LinphonePublishCleared; +}stats; + +typedef struct _LinphoneCoreManager { + LinphoneCoreVTable v_table; + LinphoneCore* lc; + stats stat; + LinphoneAddress* identity; + LinphoneEvent *lev; + bool_t decline_subscribe; +} LinphoneCoreManager; + +LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_for_proxies); +LinphoneCoreManager* linphone_core_manager_new(const char* rc_file); +void linphone_core_manager_stop(LinphoneCoreManager *mgr); +void linphone_core_manager_destroy(LinphoneCoreManager* mgr); + +void reset_counters( stats* counters); + +void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message); +void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg); +void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state); +void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf); +void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message); +void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message); +void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); +void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); +void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain); +void linphone_subscription_state_change(LinphoneCore *lc, LinphoneEvent *ev, LinphoneSubscriptionState state); +void linphone_publish_state_changed(LinphoneCore *lc, LinphoneEvent *ev, LinphonePublishState state); +void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content); + +LinphoneAddress * create_linphone_address(const char * domain); +bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value); +bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms); +bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timout_ms); + +bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr); +stats * get_stats(LinphoneCore *lc); +LinphoneCoreManager *get_manager(LinphoneCore *lc); + +#endif /* LIBLINPHONE_TESTER_H_ */ + diff --git a/tester/marie_early_rc b/tester/marie_early_rc new file mode 100644 index 000000000..844959eae --- /dev/null +++ b/tester/marie_early_rc @@ -0,0 +1,45 @@ +[sip] +sip_port=-1 +sip_tcp_port=-1 +sip_tls_port=-1 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +incoming_calls_early_media=1 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip.example.org;transport=tcp +reg_route=sip.example.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=8072 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture \ No newline at end of file diff --git a/tester/marie_no_sdp_rc b/tester/marie_no_sdp_rc new file mode 100644 index 000000000..50a740dca --- /dev/null +++ b/tester/marie_no_sdp_rc @@ -0,0 +1,48 @@ +[sip] +sip_port=5082 +sip_tcp_port=5082 +sip_tls_port=5083 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +sdp_200_ack=1 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip.example.org;transport=tcp +reg_route=sip.example.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=8072 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG diff --git a/tester/marie_rc b/tester/marie_rc new file mode 100644 index 000000000..d5b7d7c87 --- /dev/null +++ b/tester/marie_rc @@ -0,0 +1,47 @@ +[sip] +sip_port=5082 +sip_tcp_port=5082 +sip_tls_port=5083 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip.example.org;transport=tcp +reg_route=sip.example.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=9072 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/tester/message_tester.c b/tester/message_tester.c new file mode 100644 index 000000000..c3001c226 --- /dev/null +++ b/tester/message_tester.c @@ -0,0 +1,285 @@ +/* + belle-sip - SIP (RFC3261) library. + 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 3 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, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + +static char* message_external_body_url; + +void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { + stats* counters = get_stats(lc); + counters->number_of_LinphoneMessageReceivedLegacy++; +} + +void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message) { + char* from=linphone_address_as_string(linphone_chat_message_get_from(message)); + stats* counters; + ms_message("Message from [%s] is [%s] , external URL [%s]",from + ,linphone_chat_message_get_text(message) + ,linphone_chat_message_get_external_body_url(message)); + ms_free(from); + counters = get_stats(lc); + counters->number_of_LinphoneMessageReceived++; + if (linphone_chat_message_get_external_body_url(message)) { + counters->number_of_LinphoneMessageExtBodyReceived++; + CU_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url); + } +} + +void linphone_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { + LinphoneCore* lc=(LinphoneCore*)ud; + stats* counters = get_stats(lc); + ms_message("Message [%s] [%s]",linphone_chat_message_get_text(msg),linphone_chat_message_state_to_string(state)); + switch (state) { + case LinphoneChatMessageStateDelivered: + counters->number_of_LinphoneMessageDelivered++; + break; + case LinphoneChatMessageStateNotDelivered: + counters->number_of_LinphoneMessageNotDelivered++; + break; + case LinphoneChatMessageStateInProgress: + counters->number_of_LinphoneMessageInProgress++; + break; + default: + ms_error("Unexpected state [%s] for message [%p]",linphone_chat_message_state_to_string(state),msg); + } + +} + +static void text_message(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + ms_free(to); + + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_with_privacy(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneProxyConfig* pauline_proxy; + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + ms_free(to); + + /*test proxy config privacy*/ + linphone_core_get_default_proxy(pauline->lc,&pauline_proxy); + linphone_proxy_config_set_privacy(pauline_proxy,LinphonePrivacyId); + + CU_ASSERT_PTR_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageReceivedLegacy,1); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_compatibility_mode(void) { + char route[256]; + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneProxyConfig* proxy; + LinphoneAddress* proxy_address; + char*tmp; + LCSipTransports transport; + char* to = linphone_address_as_string(pauline->identity); + LinphoneChatRoom* chat_room; + + linphone_core_get_default_proxy(marie->lc,&proxy); + CU_ASSERT_PTR_NOT_NULL (proxy); + proxy_address=linphone_address_new(linphone_proxy_config_get_addr(proxy)); + linphone_address_clean(proxy_address); + tmp=linphone_address_as_string_uri_only(proxy_address); + linphone_proxy_config_set_server_addr(proxy,tmp); + sprintf(route,"sip:%s",test_route); + linphone_proxy_config_set_route(proxy,route); + ms_free(tmp); + linphone_address_destroy(proxy_address); + linphone_core_get_sip_transports(marie->lc,&transport); + transport.udp_port=0; + transport.tls_port=0; + transport.dtls_port=0; + /*only keep tcp*/ + linphone_core_set_sip_transports(marie->lc,&transport); + marie->stat.number_of_LinphoneRegistrationOk=0; + + CU_ASSERT_TRUE (wait_for(marie->lc,marie->lc,&marie->stat.number_of_LinphoneRegistrationOk,1)); + + chat_room = linphone_core_create_chat_room(marie->lc,to); + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceivedLegacy,1); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_with_ack(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_with_external_body(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + linphone_chat_message_set_external_body_url(message,message_external_body_url="http://www.linphone.org"); + linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void text_message_with_send_error(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + char* to = linphone_address_as_string(pauline->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); + LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + /*simultate a network error*/ + sal_set_send_error(marie->lc->sal, -1); + linphone_chat_room_send_message2(chat_room,message,linphone_chat_message_state_change,marie->lc); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); + /*CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageInProgress,1);*/ + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0); + + sal_set_send_error(marie->lc->sal, 0); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static const char *info_content="blabla"; + +void info_message_received(LinphoneCore *lc, LinphoneCall* call, const LinphoneInfoMessage *msg){ + stats* counters = get_stats(lc); + + if (counters->last_received_info_message) { + linphone_info_message_destroy(counters->last_received_info_message); + } + counters->last_received_info_message=linphone_info_message_copy(msg); + counters->number_of_inforeceived++; +} + + + +static void info_message_with_args(bool_t with_content) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneInfoMessage *info; + const LinphoneContent *content; + const char *hvalue; + + CU_ASSERT_TRUE(call(pauline,marie)); + + info=linphone_core_create_info_message(marie->lc); + linphone_info_message_add_header(info,"Weather","still bad"); + if (with_content) { + LinphoneContent ct={0}; + ct.type="application"; + ct.subtype="somexml"; + ct.data=(void*)info_content; + ct.size=strlen(info_content); + linphone_info_message_set_content(info,&ct); + } + linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),info); + linphone_info_message_destroy(info); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived,1)); + + CU_ASSERT_PTR_NOT_NULL(pauline->stat.last_received_info_message); + hvalue=linphone_info_message_get_header(pauline->stat.last_received_info_message, "Weather"); + content=linphone_info_message_get_content(pauline->stat.last_received_info_message); + + CU_ASSERT_PTR_NOT_NULL(hvalue); + if (hvalue) + CU_ASSERT_TRUE(strcmp(hvalue,"still bad")==0); + + if (with_content){ + CU_ASSERT_PTR_NOT_NULL(content); + if (content) { + CU_ASSERT_PTR_NOT_NULL(content->data); + CU_ASSERT_PTR_NOT_NULL(content->type); + CU_ASSERT_PTR_NOT_NULL(content->subtype); + if (content->type) CU_ASSERT_TRUE(strcmp(content->type,"application")==0); + if (content->subtype) CU_ASSERT_TRUE(strcmp(content->subtype,"somexml")==0); + if (content->data)CU_ASSERT_TRUE(strcmp((const char*)content->data,info_content)==0); + CU_ASSERT_EQUAL(content->size,strlen(info_content)); + } + } + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void info_message(){ + info_message_with_args(FALSE); +} + +static void info_message_with_body(){ + info_message_with_args(TRUE); +} + +test_t message_tests[] = { + { "Text message", text_message }, + { "Text message with privacy", text_message_with_privacy }, + { "Text message compatibility mode", text_message_compatibility_mode }, + { "Text message with ack", text_message_with_ack }, + { "Text message with send error", text_message_with_send_error }, + { "Text message with external body", text_message_with_external_body }, + { "Info message", info_message }, + { "Info message with body", info_message_with_body } +}; + +test_suite_t message_test_suite = { + "Message", + NULL, + NULL, + sizeof(message_tests) / sizeof(message_tests[0]), + message_tests +}; + diff --git a/tester/multi_account_lrc b/tester/multi_account_lrc new file mode 100644 index 000000000..a78a5bc16 --- /dev/null +++ b/tester/multi_account_lrc @@ -0,0 +1,55 @@ +[sip] +sip_port=5072 +sip_tcp_port=5072 +sip_tls_port=5073 +default_proxy=0 + +[auth_info_0] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm=auth.example.org + +[auth_info_1] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + +[auth_info_2] +username=liblinphone_tester +userid=liblinphone_tester +passwd=secret +realm=auth1.example.org + +[auth_info_3] +username=marie +userid=marie +passwd=secret +realm=sip.example.org + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tls +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_1] +reg_proxy=sip.example.org;transport=tcp +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +[proxy_2] +reg_proxy=auth1.example.org +reg_identity=sip:liblinphone_tester@auth1.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + + diff --git a/tester/pauline_alt_rc b/tester/pauline_alt_rc new file mode 100644 index 000000000..7c1fe55ac --- /dev/null +++ b/tester/pauline_alt_rc @@ -0,0 +1,20 @@ +[sip] +sip_tls_port=-1 +default_proxy=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=altname.linphone.org:5062;transport=tls +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + diff --git a/tester/pauline_rc b/tester/pauline_rc new file mode 100644 index 000000000..204486f66 --- /dev/null +++ b/tester/pauline_rc @@ -0,0 +1,46 @@ +[sip] +sip_port=5072 +sip_tcp_port=5072 +sip_tls_port=5073 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tls +reg_route=sip2.linphone.org;transport=tls +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +#[friend_0] +#url="Mariette" +#pol=accept +#subscribe=0 + +[rtp] +audio_rtp_port=8090 +video_rtp_port=9092 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/tester/pauline_wild_rc b/tester/pauline_wild_rc new file mode 100644 index 000000000..d828c807d --- /dev/null +++ b/tester/pauline_wild_rc @@ -0,0 +1,29 @@ +[sip] +sip_tls_port=-1 +default_proxy=0 +register_only_when_network_is_up=0 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip.wildcard1.linphone.org;transport=tls +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + + +[proxy_1] +reg_proxy=altname.wildcard2.linphone.org:5062;transport=tls +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + diff --git a/tester/presence_tester.c b/tester/presence_tester.c new file mode 100644 index 000000000..9f3f009f1 --- /dev/null +++ b/tester/presence_tester.c @@ -0,0 +1,352 @@ +/* + belle-sip - SIP (RFC3261) library. + 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 3 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, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + +static LinphoneCoreManager* presence_linphone_core_manager_new(char* username) { + LinphoneCoreManager* mgr= linphone_core_manager_new2( "empty_rc", FALSE); + char* identity_char; + mgr->identity= linphone_core_get_primary_contact_parsed(mgr->lc); + linphone_address_set_username(mgr->identity,username); + identity_char=linphone_address_as_string(mgr->identity); + linphone_core_set_primary_contact(mgr->lc,identity_char); + return mgr; +} +void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url){ + char* from=linphone_address_as_string(linphone_friend_get_address(lf)); + stats* counters; + ms_message("New subscription request from [%s] url [%s]",from,url); + ms_free(from); + counters = get_stats(lc); + counters->number_of_NewSubscriptionRequest++; + linphone_core_add_friend(lc,lf); /*accept subscription*/ +} + +void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf) { + stats* counters; + LinphonePresenceActivity *activity = NULL; + char* from=linphone_address_as_string(linphone_friend_get_address(lf)); + ms_message("New Notify request from [%s] ",from); + ms_free(from); + counters = get_stats(lc); + counters->number_of_NotifyReceived++; + + counters->last_received_presence = linphone_friend_get_presence_model(lf); + activity = linphone_presence_model_get_activity(counters->last_received_presence); + switch (linphone_presence_activity_get_type(activity)) { + case LinphonePresenceActivityOffline: + counters->number_of_LinphonePresenceActivityOffline++; break; + case LinphonePresenceActivityOnline: + counters->number_of_LinphonePresenceActivityOnline++; break; + case LinphonePresenceActivityAppointment: + counters->number_of_LinphonePresenceActivityAppointment++; break; + case LinphonePresenceActivityAway: + counters->number_of_LinphonePresenceActivityAway++; break; + case LinphonePresenceActivityBreakfast: + counters->number_of_LinphonePresenceActivityBreakfast++; break; + case LinphonePresenceActivityBusy: + counters->number_of_LinphonePresenceActivityBusy++; break; + case LinphonePresenceActivityDinner: + counters->number_of_LinphonePresenceActivityDinner++; break; + case LinphonePresenceActivityHoliday: + counters->number_of_LinphonePresenceActivityHoliday++; break; + case LinphonePresenceActivityInTransit: + counters->number_of_LinphonePresenceActivityInTransit++; break; + case LinphonePresenceActivityLookingForWork: + counters->number_of_LinphonePresenceActivityLookingForWork++; break; + case LinphonePresenceActivityLunch: + counters->number_of_LinphonePresenceActivityLunch++; break; + case LinphonePresenceActivityMeal: + counters->number_of_LinphonePresenceActivityMeal++; break; + case LinphonePresenceActivityMeeting: + counters->number_of_LinphonePresenceActivityMeeting++; break; + case LinphonePresenceActivityOnThePhone: + counters->number_of_LinphonePresenceActivityOnThePhone++; break; + case LinphonePresenceActivityOther: + counters->number_of_LinphonePresenceActivityOther++; break; + case LinphonePresenceActivityPerformance: + counters->number_of_LinphonePresenceActivityPerformance++; break; + case LinphonePresenceActivityPermanentAbsence: + counters->number_of_LinphonePresenceActivityPermanentAbsence++; break; + case LinphonePresenceActivityPlaying: + counters->number_of_LinphonePresenceActivityPlaying++; break; + case LinphonePresenceActivityPresentation: + counters->number_of_LinphonePresenceActivityPresentation++; break; + case LinphonePresenceActivityShopping: + counters->number_of_LinphonePresenceActivityShopping++; break; + case LinphonePresenceActivitySleeping: + counters->number_of_LinphonePresenceActivitySleeping++; break; + case LinphonePresenceActivitySpectator: + counters->number_of_LinphonePresenceActivitySpectator++; break; + case LinphonePresenceActivitySteering: + counters->number_of_LinphonePresenceActivitySteering++; break; + case LinphonePresenceActivityTravel: + counters->number_of_LinphonePresenceActivityTravel++; break; + case LinphonePresenceActivityTV: + counters->number_of_LinphonePresenceActivityTV++; break; + case LinphonePresenceActivityUnknown: + counters->number_of_LinphonePresenceActivityUnknown++; break; + case LinphonePresenceActivityVacation: + counters->number_of_LinphonePresenceActivityVacation++; break; + case LinphonePresenceActivityWorking: + counters->number_of_LinphonePresenceActivityWorking++; break; + case LinphonePresenceActivityWorship: + counters->number_of_LinphonePresenceActivityWorship++; break; + } +} + +static void wait_core(LinphoneCore *core) { + int i; + + for (i = 0; i < 10; i++) { + linphone_core_iterate(core); + ms_usleep(100000); + } +} + +static void simple_publish(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneProxyConfig* proxy; + LinphonePresenceModel* presence; + + linphone_core_get_default_proxy(marie->lc,&proxy); + linphone_proxy_config_edit(proxy); + linphone_proxy_config_enable_publish(proxy,TRUE); + linphone_proxy_config_done(proxy); + wait_core(marie->lc); + presence =linphone_presence_model_new_with_activity(LinphonePresenceActivityOffline,NULL); + linphone_core_set_presence_model(marie->lc,presence); + wait_core(marie->lc); + linphone_core_manager_destroy(marie); +} + +static bool_t subscribe_to_callee_presence(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { + stats initial_caller=caller_mgr->stat; + stats initial_callee=callee_mgr->stat; + bool_t result=FALSE; + char* identity=linphone_address_as_string_uri_only(callee_mgr->identity); + + + LinphoneFriend* friend=linphone_friend_new_with_address(identity); + linphone_friend_edit(friend); + linphone_friend_enable_subscribes(friend,TRUE); + linphone_friend_done(friend); + + linphone_core_add_friend(caller_mgr->lc,friend); + + result=wait_for(caller_mgr->lc,callee_mgr->lc,&caller_mgr->stat.number_of_LinphonePresenceActivityOnline,initial_caller.number_of_LinphonePresenceActivityOnline+1); + /*without proxy, callee cannot subscribe to caller + result&=wait_for(caller_mgr->lc,callee_mgr->lc,&callee_mgr->stat.number_of_LinphonePresenceActivityOnline,initial_callee.number_of_LinphonePresenceActivityOnline+1); + */ + + CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NewSubscriptionRequest,initial_callee.number_of_NewSubscriptionRequest+1); + /*without proxy, callee cannot subscribe to caller + CU_ASSERT_EQUAL(callee_mgr->stat.number_of_NotifyReceived,initial_callee.number_of_NotifyReceived+1); + */ + CU_ASSERT_EQUAL(caller_mgr->stat.number_of_NotifyReceived,initial_caller.number_of_NotifyReceived+1); + + ms_free(identity); + return result; + +} +static void subscribe_failure_handle_by_app(void) { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_rc"); + LinphoneProxyConfig* config; + LinphoneFriend* lf; + char* lf_identity=linphone_address_as_string_uri_only(pauline->identity); + linphone_core_get_default_proxy(marie->lc,&config); + + CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); + wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,1); /*just to wait for unsubscription even if not notified*/ + + sal_set_recv_error(marie->lc->sal, 0); /*simulate an error*/ + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationProgress,2)); + CU_ASSERT_EQUAL(linphone_proxy_config_get_error(config),LinphoneReasonIOError); + sal_set_recv_error(marie->lc->sal, 1); + + lf = linphone_core_get_friend_by_address(marie->lc,lf_identity); + linphone_friend_edit(lf); + linphone_friend_enable_subscribes(lf,FALSE); /*disable subscription*/ + linphone_friend_done(lf); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneRegistrationOk,2)); /*wait for register ok*/ + linphone_friend_edit(lf); + linphone_friend_enable_subscribes(lf,TRUE); + linphone_friend_done(lf); + CU_ASSERT_FALSE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ + + linphone_core_manager_destroy(marie); + CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,3)); /*just to wait for unsubscription even if not notified*/ + + linphone_core_manager_destroy(pauline); +} + +static void simple_subscribe(void) { + LinphoneCoreManager* marie = presence_linphone_core_manager_new("marie"); + LinphoneCoreManager* pauline = presence_linphone_core_manager_new("pauline"); + + CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); + + + linphone_core_manager_destroy(marie); + /*unsubscribe is not reported ?*/ + CU_ASSERT_FALSE(wait_for(NULL,pauline->lc,&pauline->stat.number_of_NewSubscriptionRequest,2)); /*just to wait for unsubscription even if not notified*/ + + linphone_core_manager_destroy(pauline); +} + +static void unsubscribe_while_subscribing(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneFriend* friend = linphone_friend_new_with_address("sip:toto@git.linphone.org"); /*any unexisting address*/ + linphone_friend_edit(friend); + linphone_friend_enable_subscribes(friend,TRUE); + linphone_friend_done(friend); + linphone_core_add_friend(marie->lc,friend); + linphone_core_iterate(marie->lc); + linphone_core_manager_destroy(marie); +} + +static void call_with_presence(void) { + LinphoneCoreManager* marie = presence_linphone_core_manager_new("marie"); + LinphoneCoreManager* pauline = presence_linphone_core_manager_new("pauline"); + LinphoneVideoPolicy pol={0}; + linphone_core_set_video_policy(marie->lc,&pol); + CU_ASSERT_TRUE(subscribe_to_callee_presence(marie,pauline)); + CU_ASSERT_TRUE(subscribe_to_callee_presence(pauline,marie)); + + CU_ASSERT_TRUE(call(marie,pauline)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityOnThePhone,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphonePresenceActivityOnThePhone,1)); + + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphonePresenceActivityOnline,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityOnline,1)); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void presence_information(void) { + const char *bike_description = "Riding my bike"; + const char *vacation_note = "I'm on vacation until July 4th"; + const char *vacation_lang = "en"; + const char *contact = "sip:toto@example.com"; + LinphoneCoreManager *marie = presence_linphone_core_manager_new("marie"); + LinphoneCoreManager *pauline = presence_linphone_core_manager_new("pauline"); + LinphonePresenceModel *presence; + LinphonePresenceActivity *activity = NULL; + LinphonePresenceNote *note = NULL; + const char *description = NULL; + const char *note_content = NULL; + char *contact2; + time_t current_timestamp, presence_timestamp; + + CU_ASSERT_TRUE(subscribe_to_callee_presence(marie, pauline)); + + /* Presence activity without description. */ + presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityDinner, NULL); + linphone_core_set_presence_model(pauline->lc, presence); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityDinner,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityDinner, 1); + activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); + CU_ASSERT_PTR_NOT_NULL(activity); + CU_ASSERT_EQUAL(linphone_presence_activity_get_type(activity), LinphonePresenceActivityDinner); + description = linphone_presence_activity_get_description(activity); + CU_ASSERT_PTR_NULL(description); + + /* Presence activity with description. */ + presence = linphone_presence_model_new_with_activity(LinphonePresenceActivitySteering, bike_description); + linphone_core_set_presence_model(pauline->lc, presence); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivitySteering,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivitySteering, 1); + activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); + CU_ASSERT_PTR_NOT_NULL(activity); + CU_ASSERT_EQUAL(linphone_presence_activity_get_type(activity), LinphonePresenceActivitySteering); + description = linphone_presence_activity_get_description(activity); + CU_ASSERT_PTR_NOT_NULL(description); + if (description != NULL) CU_ASSERT_EQUAL(strcmp(description, bike_description), 0); + + /* Presence activity with description and note. */ + presence = linphone_presence_model_new_with_activity_and_note(LinphonePresenceActivityVacation, NULL, vacation_note, vacation_lang); + linphone_core_set_presence_model(pauline->lc, presence); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityVacation,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityVacation, 1); + activity = linphone_presence_model_get_activity(marie->stat.last_received_presence); + CU_ASSERT_PTR_NOT_NULL(activity); + CU_ASSERT_EQUAL(linphone_presence_activity_get_type(activity), LinphonePresenceActivityVacation); + description = linphone_presence_activity_get_description(activity); + CU_ASSERT_PTR_NULL(description); + note = linphone_presence_model_get_note(marie->stat.last_received_presence, NULL); + CU_ASSERT_PTR_NOT_NULL(note); + if (note != NULL) { + note_content = linphone_presence_note_get_content(note); + CU_ASSERT_PTR_NOT_NULL(note_content); + if (note_content != NULL) { + CU_ASSERT_EQUAL(strcmp(note_content, vacation_note), 0); + } + } + + /* Presence contact. */ + presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityOnThePhone, NULL); + linphone_presence_model_set_contact(presence, contact); + linphone_core_set_presence_model(pauline->lc, presence); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityOnThePhone,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityOnThePhone, 1); + contact2 = linphone_presence_model_get_contact(presence); + CU_ASSERT_PTR_NOT_NULL(contact2); + if (contact2 != NULL) { + CU_ASSERT_EQUAL(strcmp(contact, contact2), 0); + ms_free(contact2); + } + + /* Presence timestamp. */ + current_timestamp = time(NULL); + presence = linphone_presence_model_new_with_activity(LinphonePresenceActivityShopping, NULL); + linphone_core_set_presence_model(pauline->lc, presence); + wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePresenceActivityShopping,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePresenceActivityShopping, 1); + presence_timestamp = linphone_presence_model_get_timestamp(presence); + CU_ASSERT_TRUE(presence_timestamp >= current_timestamp); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +test_t presence_tests[] = { + { "Simple Subscribe", simple_subscribe }, + { "Simple Publish", simple_publish }, + { "Call with presence", call_with_presence }, + { "Unsubscribe while subscribing", unsubscribe_while_subscribing }, + { "Presence information", presence_information }, + { "App managed presence failure", subscribe_failure_handle_by_app }, +}; + +test_suite_t presence_test_suite = { + "Presence", + NULL, + NULL, + sizeof(presence_tests) / sizeof(presence_tests[0]), + presence_tests +}; + diff --git a/tester/register_tester.c b/tester/register_tester.c new file mode 100644 index 000000000..9531c1447 --- /dev/null +++ b/tester/register_tester.c @@ -0,0 +1,635 @@ +/* + belle-sip - SIP (RFC3261) library. + 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 3 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, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + +static LinphoneCoreManager* create_lcm_with_auth(unsigned int with_auth) { + LinphoneCoreManager* mgr=linphone_core_manager_new(NULL); + + if (with_auth) { + mgr->lc->vtable.auth_info_requested=auth_info_requested; + } + + /*to allow testing with 127.0.0.1*/ + linphone_core_set_network_reachable(mgr->lc,TRUE); + return mgr; +} + +static LinphoneCoreManager* create_lcm() { + return create_lcm_with_auth(0); +} + +void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){ + stats* counters; + ms_message("New registration state %s for user id [%s] at proxy [%s]\n" + ,linphone_registration_state_to_string(cstate) + ,linphone_proxy_config_get_identity(cfg) + ,linphone_proxy_config_get_addr(cfg)); + counters = get_stats(lc); + switch (cstate) { + case LinphoneRegistrationNone:counters->number_of_LinphoneRegistrationNone++;break; + case LinphoneRegistrationProgress:counters->number_of_LinphoneRegistrationProgress++;break; + case LinphoneRegistrationOk:counters->number_of_LinphoneRegistrationOk++;break; + case LinphoneRegistrationCleared:counters->number_of_LinphoneRegistrationCleared++;break; + case LinphoneRegistrationFailed:counters->number_of_LinphoneRegistrationFailed++;break; + default: + CU_FAIL("unexpected event");break; + } + +} + +static void register_with_refresh_base_3(LinphoneCore* lc + , bool_t refresh + ,const char* domain + ,const char* route + ,bool_t late_auth_info + ,LCSipTransports transport + ,LinphoneRegistrationState expected_final_state) { + int retry=0; + char* addr; + LinphoneProxyConfig* proxy_cfg; + stats* counters; + LinphoneAddress *from; + const char* server_addr; + LinphoneAuthInfo *info; + + CU_ASSERT_PTR_NOT_NULL(lc); + if (!lc) return; + counters = get_stats(lc); + reset_counters(counters); + linphone_core_set_sip_transports(lc,&transport); + + proxy_cfg = linphone_proxy_config_new(); + + from = create_linphone_address(domain); + + linphone_proxy_config_set_identity(proxy_cfg,addr=linphone_address_as_string(from)); + ms_free(addr); + server_addr = linphone_address_get_domain(from); + + linphone_proxy_config_enable_register(proxy_cfg,TRUE); + linphone_proxy_config_set_expires(proxy_cfg,1); + if (route) { + linphone_proxy_config_set_route(proxy_cfg,route); + linphone_proxy_config_set_server_addr(proxy_cfg,route); + } else { + linphone_proxy_config_set_server_addr(proxy_cfg,server_addr); + } + linphone_address_destroy(from); + + linphone_core_add_proxy_config(lc,proxy_cfg); + linphone_core_set_default_proxy(lc,proxy_cfg); + + while (counters->number_of_LinphoneRegistrationOk<1+(refresh!=0) && retry++ <310) { + linphone_core_iterate(lc); + if (counters->number_of_auth_info_requested>0 && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationFailed && late_auth_info) { + if (!linphone_core_get_auth_info_list(lc)) { + CU_ASSERT_EQUAL(linphone_proxy_config_get_error(proxy_cfg),LinphoneReasonUnauthorized); + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ + } + } + if (linphone_proxy_config_get_error(proxy_cfg) == LinphoneReasonBadCredentials) + break; /*no need to continue*/ + ms_usleep(100000); + } + CU_ASSERT_EQUAL(linphone_proxy_config_is_registered(proxy_cfg),(expected_final_state == LinphoneRegistrationOk)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationNone,0); + CU_ASSERT_TRUE(counters->number_of_LinphoneRegistrationProgress>=1); + if (expected_final_state == LinphoneRegistrationOk) { + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1+(refresh!=0)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,late_auth_info?1:0); + } else + /*checking to be done outside this functions*/ + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); + +} + +static void register_with_refresh_base_2(LinphoneCore* lc + , bool_t refresh + ,const char* domain + ,const char* route + ,bool_t late_auth_info + ,LCSipTransports transport) { + register_with_refresh_base_3(lc, refresh, domain, route, late_auth_info, transport,LinphoneRegistrationOk ); +} +static void register_with_refresh_base(LinphoneCore* lc, bool_t refresh,const char* domain,const char* route) { + LCSipTransports transport = {5070,5070,0,5071}; + register_with_refresh_base_2(lc,refresh,domain,route,FALSE,transport); +} + +static void register_with_refresh(LinphoneCoreManager* lcm, bool_t refresh,const char* domain,const char* route) { + stats* counters = &lcm->stat; + register_with_refresh_base(lcm->lc,refresh,domain,route); + linphone_core_manager_stop(lcm); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,1); +} + +static void register_with_refresh_with_send_error() { + int retry=0; + LinphoneCoreManager* lcm = create_lcm_with_auth(1); + stats* counters = &lcm->stat; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + char route[256]; + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh_base(lcm->lc,TRUE,auth_domain,route); + /*simultate a network error*/ + sal_set_send_error(lcm->lc->sal, -1); + while (counters->number_of_LinphoneRegistrationProgress<2 && retry++ <20) { + linphone_core_iterate(lcm->lc); + ms_usleep(100000); + } + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2); + + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); + + linphone_core_manager_destroy(lcm); +} + +static void simple_register(){ + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + register_with_refresh(lcm,FALSE,NULL,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); + linphone_core_manager_destroy(lcm); +} + +/*take care of min expires configuration from server*/ +static void simple_register_with_refresh() { + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + register_with_refresh(lcm,TRUE,NULL,NULL); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); + linphone_core_manager_destroy(lcm); +} + +static void simple_auth_register_with_refresh() { + LinphoneCoreManager* lcm = create_lcm_with_auth(1); + stats* counters = &lcm->stat; + char route[256]; + sprintf(route,"sip:%s",test_route); + register_with_refresh(lcm,TRUE,auth_domain,route); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + linphone_core_manager_destroy(lcm); +} + +static void simple_tcp_register(){ + char route[256]; + LinphoneCoreManager* lcm; + sprintf(route,"sip:%s;transport=tcp",test_route); + lcm = create_lcm(); + register_with_refresh(lcm,FALSE,test_domain,route); + linphone_core_manager_destroy(lcm); +} + +static void simple_tcp_register_compatibility_mode(){ + char route[256]; + LinphoneCoreManager* lcm; + LCSipTransports transport = {0,5070,0,0}; + sprintf(route,"sip:%s",test_route); + lcm = create_lcm(); + register_with_refresh_base_2(lcm->lc,FALSE,test_domain,route,FALSE,transport); + linphone_core_manager_destroy(lcm); +} + + +static void simple_tls_register(){ + char route[256]; + LinphoneCoreManager* lcm; + sprintf(route,"sip:%s;transport=tls",test_route); + lcm = create_lcm(); + register_with_refresh(lcm,FALSE,test_domain,route); + linphone_core_manager_destroy(lcm); +} + + +static void simple_authenticated_register(){ + stats* counters; + LinphoneCoreManager* lcm = create_lcm(); + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + char route[256]; + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + counters = &lcm->stat; + register_with_refresh(lcm,FALSE,auth_domain,route); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); +} + +static void ha1_authenticated_register(){ + stats* counters; + LinphoneCoreManager* lcm = create_lcm(); + char ha1[33]; + LinphoneAuthInfo *info; + char route[256]; + sal_auth_compute_ha1(test_username,auth_domain,test_password,ha1); + info=linphone_auth_info_new(test_username,NULL,NULL,ha1,auth_domain,NULL); /*create authentication structure from identity*/ + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + counters = &lcm->stat; + register_with_refresh(lcm,FALSE,auth_domain,route); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,0); +} + +static void authenticated_register_with_no_initial_credentials(){ + LinphoneCoreManager *mgr; + stats* counters; + char route[256]; + + sprintf(route,"sip:%s",test_route); + + mgr = linphone_core_manager_new(NULL); + + counters= get_stats(mgr->lc); + counters->number_of_auth_info_requested=0; + register_with_refresh(mgr,FALSE,auth_domain,route); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + linphone_core_manager_destroy(mgr); +} + +static void auth_info_requested2(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { + stats* counters; + ms_message("Auth info requested for user id [%s] at realm [%s]\n" + ,username + ,realm); + counters = get_stats(lc); + counters->number_of_auth_info_requested++; +} + +static void authenticated_register_with_late_credentials(){ + LinphoneCoreManager *mgr; + stats* counters; + LCSipTransports transport = {5070,5070,0,5071}; + char route[256]; + + sprintf(route,"sip:%s",test_route); + + mgr = linphone_core_manager_new(NULL); + mgr->lc->vtable.auth_info_requested=auth_info_requested2; + counters = get_stats(mgr->lc); + register_with_refresh_base_2(mgr->lc,FALSE,auth_domain,route,TRUE,transport); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + linphone_core_manager_destroy(mgr); +} + +static void authenticated_register_with_wrong_late_credentials(){ + LinphoneCoreManager *mgr; + stats* counters; + LCSipTransports transport = {5070,5070,0,5071}; + char route[256]; + const char* saved_test_passwd=test_password; + char* wrong_passwd="mot de pass tout pourrit"; + + test_password=wrong_passwd; + + sprintf(route,"sip:%s",test_route); + + mgr = linphone_core_manager_new(NULL); + mgr->lc->vtable.auth_info_requested=auth_info_requested2; + counters = get_stats(mgr->lc); + register_with_refresh_base_3(mgr->lc,FALSE,auth_domain,route,TRUE,transport,LinphoneRegistrationFailed); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,2); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,2); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,2); + test_password=saved_test_passwd; + + linphone_core_manager_destroy(mgr); +} + +static void authenticated_register_with_wrong_credentials(){ + LinphoneCoreManager *mgr; + stats* counters; + LCSipTransports transport = {5070,5070,0,5071}; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,"wrong passwd",NULL,auth_domain,NULL); /*create authentication structure from identity*/ + char route[256]; + + sprintf(route,"sip:%s",test_route); + + mgr=linphone_core_manager_new(NULL); + mgr->lc->vtable.auth_info_requested=auth_info_requested2; + + linphone_core_add_auth_info(mgr->lc,info); /*add wrong authentication info to LinphoneCore*/ + counters = get_stats(mgr->lc); + register_with_refresh_base_3(mgr->lc,TRUE,auth_domain,route,TRUE,transport,LinphoneRegistrationFailed); + CU_ASSERT_EQUAL(counters->number_of_auth_info_requested,1); + linphone_core_manager_destroy(mgr); +} + +static LinphoneCoreManager* configure_lcm(void) { + LinphoneCoreManager *mgr=linphone_core_manager_new( "multi_account_lrc"); + stats *counters=&mgr->stat; + CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&counters->number_of_LinphoneRegistrationOk,ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)))); + return mgr; +} + +static void multiple_proxy(){ + LinphoneCoreManager *mgr=configure_lcm(); + linphone_core_manager_destroy(mgr); +} + +static void network_state_change(){ + int register_ok; + stats *counters; + LinphoneCoreManager *mgr=configure_lcm(); + LinphoneCore *lc=mgr->lc; + + counters = get_stats(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + linphone_core_set_network_reachable(lc,FALSE); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationNone,register_ok)); + linphone_core_set_network_reachable(lc,TRUE); + wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,2*register_ok); + linphone_core_manager_destroy(mgr); +} +static int get_number_of_udp_proxy(const LinphoneCore* lc) { + int number_of_udp_proxy=0; + LinphoneProxyConfig* proxy_cfg; + MSList* proxys; + for (proxys=(MSList*)linphone_core_get_proxy_config_list(lc);proxys!=NULL;proxys=proxys->next) { + proxy_cfg=(LinphoneProxyConfig*)proxys->data; + if (strcmp("udp",linphone_proxy_config_get_transport(proxy_cfg))==0) + number_of_udp_proxy++; + } + return number_of_udp_proxy; +} +static void transport_change(){ + LinphoneCoreManager *mgr; + LinphoneCore* lc; + int register_ok; + stats* counters ; + LCSipTransports sip_tr; + LCSipTransports sip_tr_orig; + int number_of_udp_proxy=0; + int total_number_of_proxies; + memset(&sip_tr,0,sizeof(sip_tr)); + + mgr=configure_lcm(); + lc=mgr->lc; + counters = get_stats(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + + number_of_udp_proxy=get_number_of_udp_proxy(lc); + total_number_of_proxies=ms_list_size(linphone_core_get_proxy_config_list(lc)); + linphone_core_get_sip_transports(lc,&sip_tr_orig); + + sip_tr.udp_port=sip_tr_orig.udp_port; + + /*keep only udp*/ + linphone_core_set_sip_transports(lc,&sip_tr); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok+number_of_udp_proxy)); + + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationFailed,total_number_of_proxies-number_of_udp_proxy)); + + linphone_core_manager_destroy(mgr); +} + +static void io_recv_error(){ + LinphoneCoreManager *mgr; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + + + mgr=configure_lcm(); + lc=mgr->lc; + counters = get_stats(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + number_of_udp_proxy=get_number_of_udp_proxy(lc); + sal_set_recv_error(lc->sal, 0); + + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationProgress,2*(register_ok-number_of_udp_proxy) /*because 1 udp*/)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) + + sal_set_recv_error(lc->sal, 1); /*reset*/ + + linphone_core_manager_destroy(mgr); +} + +static void io_recv_error_retry_immediatly(){ + LinphoneCoreManager *mgr; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + + + mgr=configure_lcm(); + lc=mgr->lc; + counters = get_stats(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + number_of_udp_proxy=get_number_of_udp_proxy(lc); + sal_set_recv_error(lc->sal, 0); + + CU_ASSERT_TRUE(wait_for(lc,NULL,&counters->number_of_LinphoneRegistrationProgress,(register_ok-number_of_udp_proxy)+register_ok /*because 1 udp*/)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) + sal_set_recv_error(lc->sal, 1); /*reset*/ + + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationOk,register_ok-number_of_udp_proxy+register_ok)); + + linphone_core_manager_destroy(mgr); +} + +static void io_recv_error_late_recovery(){ + LinphoneCoreManager *mgr; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + MSList* lcs; + + mgr=linphone_core_manager_new2( "multi_account_lrc",FALSE); /*to make sure iterates are not call yet*/ + lc=mgr->lc; + sal_set_refresher_retry_after(lc->sal,1000); + counters=&mgr->stat; + CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&counters->number_of_LinphoneRegistrationOk,ms_list_size(linphone_core_get_proxy_config_list(mgr->lc)))); + + + counters = get_stats(lc); + register_ok=counters->number_of_LinphoneRegistrationOk; + number_of_udp_proxy=get_number_of_udp_proxy(lc); + /*simulate a general socket error*/ + sal_set_recv_error(lc->sal, 0); + sal_set_send_error(lc->sal, -1); + + CU_ASSERT_TRUE(wait_for(lc,NULL,&counters->number_of_LinphoneRegistrationProgress,(register_ok-number_of_udp_proxy)+register_ok /*because 1 udp*/)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) + + CU_ASSERT_TRUE(wait_for_list(lcs=ms_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationFailed,(register_ok-number_of_udp_proxy),sal_get_refresher_retry_after(lc->sal)+1000)); + + sal_set_recv_error(lc->sal, 1); /*reset*/ + sal_set_send_error(lc->sal, 0); + + CU_ASSERT_TRUE(wait_for_list(lcs=ms_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationOk,register_ok-number_of_udp_proxy +register_ok,sal_get_refresher_retry_after(lc->sal)+1000)); + + linphone_core_manager_destroy(mgr); +} + +static void io_recv_error_without_active_register(){ + LinphoneCoreManager *mgr; + LinphoneCore* lc; + int register_ok; + stats* counters ; + int number_of_udp_proxy=0; + MSList* proxys; + + mgr=configure_lcm(); + lc=mgr->lc; + counters = get_stats(lc); + + register_ok=counters->number_of_LinphoneRegistrationOk; + number_of_udp_proxy=get_number_of_udp_proxy(lc); + + for (proxys=ms_list_copy(linphone_core_get_proxy_config_list(lc));proxys!=NULL;proxys=proxys->next) { + LinphoneProxyConfig* proxy_cfg=(LinphoneProxyConfig*)proxys->data; + linphone_proxy_config_edit(proxy_cfg); + linphone_proxy_config_enable_register(proxy_cfg,FALSE); + linphone_proxy_config_done(proxy_cfg); + } + ms_list_free(proxys); + CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationCleared,register_ok /*because 1 udp*/)); + + sal_set_recv_error(lc->sal, 0); + + /*nothing should happen because no active registration*/ + CU_ASSERT_FALSE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationProgress,2*(register_ok-number_of_udp_proxy) /*because 1 udp*/)); + + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) + + sal_set_recv_error(lc->sal, 1); /*reset*/ + + linphone_core_manager_destroy(mgr); +} + + +static void tls_certificate_failure(){ + LinphoneCoreManager* mgr; + LinphoneCore *lc; + char rootcapath[256]; + + mgr=linphone_core_manager_new2("pauline_rc",FALSE); + lc=mgr->lc; + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/agent.pem", liblinphone_tester_file_prefix); /*bad root ca*/ + linphone_core_set_root_ca(mgr->lc,rootcapath); + linphone_core_set_network_reachable(lc,TRUE); + CU_ASSERT_TRUE(wait_for(mgr->lc,mgr->lc,&mgr->stat.number_of_LinphoneRegistrationFailed,1)); + linphone_core_set_root_ca(mgr->lc,NULL); /*no root ca*/ + linphone_core_refresh_registers(mgr->lc); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationFailed,2)); + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cafile.pem", liblinphone_tester_file_prefix); /*goot root ca*/ + linphone_core_set_root_ca(mgr->lc,rootcapath); + linphone_core_refresh_registers(mgr->lc); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); + CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationFailed,2); + linphone_core_destroy(mgr->lc); +} + +static void tls_with_non_tls_server(){ + LinphoneCoreManager *mgr; + LinphoneProxyConfig* proxy_cfg; + LinphoneAddress* addr; + char tmp[256]; + LinphoneCore *lc; + + mgr=linphone_core_manager_new2( "marie_rc", 0); + lc=mgr->lc; + linphone_core_get_default_proxy(lc,&proxy_cfg); + linphone_proxy_config_edit(proxy_cfg); + addr=linphone_address_new(linphone_proxy_config_get_addr(proxy_cfg)); + snprintf(tmp,sizeof(tmp),"sip:%s:%i;transport=tls" ,linphone_address_get_domain(addr) + ,(linphone_address_get_port(addr)>0?linphone_address_get_port(addr):5060)); + linphone_proxy_config_set_server_addr(proxy_cfg,tmp); + linphone_proxy_config_done(proxy_cfg); + linphone_address_destroy(addr); + /* FIXME http://git.linphone.org/mantis/view.php?id=758 + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationFailed,1)); + */ + linphone_core_manager_destroy(mgr); +} + +static void tls_alt_name_register(){ + LinphoneCoreManager* mgr; + LinphoneCore *lc; + char rootcapath[256]; + + mgr=linphone_core_manager_new2("pauline_alt_rc",FALSE); + lc=mgr->lc; + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cafile.pem", liblinphone_tester_file_prefix); + linphone_core_set_root_ca(mgr->lc,rootcapath); + linphone_core_refresh_registers(mgr->lc); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,1)); + CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationFailed,0); + linphone_core_destroy(mgr->lc); +} + +static void tls_wildcard_register(){ + LinphoneCoreManager* mgr; + LinphoneCore *lc; + char rootcapath[256]; + + mgr=linphone_core_manager_new2("pauline_wild_rc",FALSE); + lc=mgr->lc; + snprintf(rootcapath,sizeof(rootcapath), "%s/certificates/cn/cafile.pem", liblinphone_tester_file_prefix); + linphone_core_set_root_ca(mgr->lc,rootcapath); + linphone_core_refresh_registers(mgr->lc); + CU_ASSERT_TRUE(wait_for(lc,lc,&mgr->stat.number_of_LinphoneRegistrationOk,2)); + CU_ASSERT_EQUAL(mgr->stat.number_of_LinphoneRegistrationFailed,0); + linphone_core_destroy(mgr->lc); +} + +test_t register_tests[] = { + { "Simple register", simple_register }, + { "TCP register", simple_tcp_register }, + { "TCP register compatibility mode", simple_tcp_register_compatibility_mode }, + { "TLS register", simple_tls_register }, + { "TLS register with alt. name certificate", tls_alt_name_register }, + { "TLS register with wildcard certificate", tls_wildcard_register }, + { "TLS certificate not verified",tls_certificate_failure}, + { "TLS with non tls server",tls_with_non_tls_server}, + { "Simple authenticated register", simple_authenticated_register }, + { "Ha1 authenticated register", ha1_authenticated_register }, + { "Digest auth without initial credentials", authenticated_register_with_no_initial_credentials }, + { "Digest auth with wrong credentials", authenticated_register_with_wrong_credentials }, + { "Authenticated register with wrong late credentials", authenticated_register_with_wrong_late_credentials}, + { "Authenticated register with late credentials", authenticated_register_with_late_credentials }, + { "Register with refresh", simple_register_with_refresh }, + { "Authenticated register with refresh", simple_auth_register_with_refresh }, + { "Register with refresh and send error", register_with_refresh_with_send_error }, + { "Multi account", multiple_proxy }, + { "Transport change", transport_change }, + { "Network state change", network_state_change }, + { "Io recv error", io_recv_error }, + { "Io recv error with recovery", io_recv_error_retry_immediatly}, + { "Io recv error with late recovery", io_recv_error_late_recovery}, + { "Io recv error without active registration", io_recv_error_without_active_register} +}; + +test_suite_t register_test_suite = { + "Register", + NULL, + NULL, + sizeof(register_tests) / sizeof(register_tests[0]), + register_tests +}; + diff --git a/tester/setup_tester.c b/tester/setup_tester.c new file mode 100644 index 000000000..7a5bac9c9 --- /dev/null +++ b/tester/setup_tester.c @@ -0,0 +1,109 @@ +/* + belle-sip - SIP (RFC3261) library. + 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 3 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, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "liblinphone_tester.h" +#include "lpconfig.h" + + +static void core_init_test(void) { + LinphoneCoreVTable v_table; + LinphoneCore* lc; + memset (&v_table,0,sizeof(v_table)); + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + /* until we have good certificates on our test server... */ + linphone_core_verify_server_certificates(lc,FALSE); + CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + linphone_core_destroy(lc); +} + +static void linphone_address_test(void) { + linphone_address_destroy(create_linphone_address(NULL)); +} + +static void core_sip_transport_test(void) { + LinphoneCoreVTable v_table; + LinphoneCore* lc; + LCSipTransports tr; + memset (&v_table,0,sizeof(v_table)); + lc = linphone_core_new(&v_table,NULL,NULL,NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL(lc); + linphone_core_get_sip_transports(lc,&tr); + CU_ASSERT_EQUAL(tr.udp_port,5060); /*default config*/ + CU_ASSERT_EQUAL(tr.tcp_port,0); /*default config*/ + CU_ASSERT_EQUAL(tr.tls_port,0); /*default config*/ + + tr.udp_port=LC_SIP_TRANSPORT_RANDOM; + tr.tcp_port=LC_SIP_TRANSPORT_RANDOM; + tr.tls_port=LC_SIP_TRANSPORT_RANDOM; + + linphone_core_set_sip_transports(lc,&tr); + linphone_core_get_sip_transports(lc,&tr); + + CU_ASSERT_NOT_EQUAL(tr.udp_port,5060); /*default config*/ + CU_ASSERT_NOT_EQUAL(tr.tcp_port,0); /*default config*/ + CU_ASSERT_NOT_EQUAL(tr.tls_port,0); /*default config*/ + + CU_ASSERT_EQUAL(lp_config_get_int(linphone_core_get_config(lc),"sip","sip_port",-2),LC_SIP_TRANSPORT_RANDOM); + CU_ASSERT_EQUAL(lp_config_get_int(linphone_core_get_config(lc),"sip","sip_tcp_port",-2),LC_SIP_TRANSPORT_RANDOM); + CU_ASSERT_EQUAL(lp_config_get_int(linphone_core_get_config(lc),"sip","sip_tls_port",-2),LC_SIP_TRANSPORT_RANDOM); + + linphone_core_destroy(lc); +} + +static void linphone_interpret_url_test() +{ + LinphoneCoreVTable v_table; + LinphoneCore* lc; + const char* sips_address = "sips:margaux@sip.linphone.org"; + LinphoneAddress* address; + + memset ( &v_table,0,sizeof ( v_table ) ); + lc = linphone_core_new ( &v_table,NULL,NULL,NULL ); + CU_ASSERT_PTR_NOT_NULL_FATAL ( lc ); + + address = linphone_core_interpret_url(lc, sips_address); + + CU_ASSERT_PTR_NOT_NULL_FATAL(address); + CU_ASSERT_STRING_EQUAL_FATAL(linphone_address_get_scheme(address), "sips"); + CU_ASSERT_STRING_EQUAL_FATAL(linphone_address_get_username(address), "margaux"); + CU_ASSERT_STRING_EQUAL_FATAL(linphone_address_get_domain(address), "sip.linphone.org"); + + linphone_address_destroy(address); + + linphone_core_destroy ( lc ); +} + + +test_t setup_tests[] = { + { "Linphone Address", linphone_address_test }, + { "Linphone core init/uninit", core_init_test }, + { "Linphone random transport port",core_sip_transport_test}, + { "Linphone interpret url", linphone_interpret_url_test } +}; + +test_suite_t setup_test_suite = { + "Setup", + NULL, + NULL, + sizeof(setup_tests) / sizeof(setup_tests[0]), + setup_tests +}; + diff --git a/tester/sounds/hello8000.wav b/tester/sounds/hello8000.wav new file mode 100644 index 000000000..b787b202e Binary files /dev/null and b/tester/sounds/hello8000.wav differ diff --git a/tester/sounds/oldphone.wav b/tester/sounds/oldphone.wav new file mode 100644 index 000000000..e3056cc5d Binary files /dev/null and b/tester/sounds/oldphone.wav differ diff --git a/tester/sounds/ringback.wav b/tester/sounds/ringback.wav new file mode 100644 index 000000000..21f4b5bfb Binary files /dev/null and b/tester/sounds/ringback.wav differ diff --git a/tester/tester_hosts b/tester/tester_hosts new file mode 100644 index 000000000..b7056b863 --- /dev/null +++ b/tester/tester_hosts @@ -0,0 +1 @@ +94.23.19.176 sip2.linphone.org sip.example.org sipopen.example.org auth.example.org auth1.example.org auth2.example.org altname.linphone.org sip.wildcard1.linphone.org altname.wildcard2.linphone.org diff --git a/tester/upnp_rc b/tester/upnp_rc new file mode 100644 index 000000000..3b04fd077 --- /dev/null +++ b/tester/upnp_rc @@ -0,0 +1,2 @@ + [net] + firewall_policy=4 diff --git a/tester/upnp_tester.c b/tester/upnp_tester.c new file mode 100644 index 000000000..8b1d13e1d --- /dev/null +++ b/tester/upnp_tester.c @@ -0,0 +1,65 @@ +/* + belle-sip - SIP (RFC3261) library. + 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 3 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, see . +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "lpconfig.h" +#include "private.h" +#include "liblinphone_tester.h" + +static void upnp_start_n_stop(void) { + int tmp = 0; + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); + wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); +#ifdef BUILD_UPNP + CU_ASSERT_TRUE(lc_upnp->lc->upnp != NULL); +#endif + linphone_core_manager_destroy(lc_upnp); +} + +static void upnp_check_state(void) { + int tmp = 0; + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); + wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); + CU_ASSERT_TRUE(linphone_core_get_upnp_state(lc_upnp->lc) == LinphoneUpnpStateOk); + linphone_core_manager_destroy(lc_upnp); +} + +static void upnp_check_ipaddress(void) { + int tmp = 0; + LinphoneCoreManager* lc_upnp = linphone_core_manager_new2( "upnp_rc", FALSE); + wait_for(lc_upnp->lc,lc_upnp->lc,&tmp,1); + const char *addr = linphone_core_get_upnp_external_ipaddress(lc_upnp->lc); + CU_ASSERT_TRUE(addr != NULL && strlen(addr)>=7); + linphone_core_manager_destroy(lc_upnp); +} + +test_t upnp_tests[] = { + { "Start and stop", upnp_start_n_stop }, + { "Check state", upnp_check_state }, + { "Check ip address", upnp_check_ipaddress }, +}; + +test_suite_t upnp_test_suite = { + "Upnp", + NULL, + NULL, + sizeof(upnp_tests) / sizeof(upnp_tests[0]), + upnp_tests +}; diff --git a/tester/userdb.conf b/tester/userdb.conf new file mode 100644 index 000000000..3ee1b7e0a --- /dev/null +++ b/tester/userdb.conf @@ -0,0 +1,9 @@ +liblinphone_tester@sip.example.org secret +liblinphone_tester@auth.example.org secret +liblinphone_tester@auth1.example.org secret +tester@sip.example.org secret + +pauline@sip.example.org secret +marie@sip.example.org secret +laure@sip.example.org secret +bellesip@sip.example.org secret diff --git a/tools/Makefile.am b/tools/Makefile.am index a93d809f1..5ef2535ad 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -2,15 +2,18 @@ AM_CPPFLAGS=\ -I$(top_srcdir) \ - -I$(top_srcdir)/coreapi \ - -I$(top_srcdir)/exosip + -I$(top_srcdir)/coreapi COMMON_CFLAGS=\ -DIN_LINPHONE \ $(ORTP_CFLAGS) \ + $(MEDIASTREAMER_CFLAGS) \ $(STRICT_OPTIONS) \ $(LIBXML2_CFLAGS) +#-fpermissive to workaround a g++ bug on macos 32bit SDK. +AM_CXXFLAGS=$(LIBXML2_CFLAGS) -fpermissive $(STRICT_OPTIONS) + EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc if BUILD_TOOLS @@ -38,7 +41,7 @@ liblpc2xml_la_LIBADD=\ libxml2lpc_la_LDFLAGS=-no-undefined liblpc2xml_la_LDFLAGS=-no-undefined -bin_PROGRAMS=xml2lpc_test lpc2xml_test +bin_PROGRAMS=xml2lpc_test lpc2xml_test lp-gen-wrappers xml2lpc_test_SOURCES=\ xml2lpc_test.c @@ -54,7 +57,15 @@ xml2lpc_test_LDADD=\ lpc2xml_test_CFLAGS=$(COMMON_CFLAGS) lpc2xml_test_LDADD=\ $(top_builddir)/coreapi/liblinphone.la \ - liblpc2xml.la + liblpc2xml.la + +lp_gen_wrappers_SOURCES=genwrappers.cc \ + software-desc.cc software-desc.hh \ + generator.cc generator.hh + +lp_gen_wrappers_LDADD= \ + $(LIBXML2_LIBS) + endif diff --git a/tools/generator.cc b/tools/generator.cc new file mode 100644 index 000000000..82f50c660 --- /dev/null +++ b/tools/generator.cc @@ -0,0 +1,453 @@ +/* +linphone +Copyright (C) 2013 Belledonne Communications SARL +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 + +#include "generator.hh" + +#ifdef WIN32 +#include +#endif + + +string to_lower(const string &str){ + string res=str; + for(string::iterator it=res.begin();it!=res.end();++it){ + *it=tolower(*it); + } + return res; +} + +CplusplusGenerator::CplusplusGenerator(){ +} + +void CplusplusGenerator::generate(Project *proj){ + list classes=proj->getClasses(); + mCurProj=proj; +#ifndef WIN32 + mkdir(proj->getName().c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH); +#else + _mkdir(proj->getName().c_str()); +#endif + for_each(classes.begin(),classes.end(),bind1st(mem_fun(&CplusplusGenerator::writeClass),this)); +} + +void CplusplusGenerator::writeEnumMember(ConstField *cf, bool isLast){ + writeTabs(1); + mOutfile<getName(); + if (!isLast) mOutfile<<","; + if (!cf->getHelp().empty()) mOutfile<<"\t/**< "<getHelp()<<" */"; + mOutfile<getName()<<"/"<getName()<<".hh"; + mOutfile.open(filename.str().c_str()); + if (!mOutfile.is_open()){ + cerr<<"Could not write into "< methods=klass->getMethods(); + list constFields=klass->getConstFields(); + mCurClass=klass; + mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<"<getName().empty()) + mOutfile<<"namespace "<getName()<<"{"<getType()==Type::Enum){ + mOutfile<<"enum "<getName()<<"{"<::iterator cfit,next; + for (cfit=constFields.begin();cfit!=constFields.end();){ + ConstField *cf=*cfit; + writeEnumMember(cf,++cfit==constFields.end()); + } + }else{ + mOutfile<<"class "<getName()<<"{"<getName().empty()) + mOutfile<<"} //end of namespace "<getName()<getType(); + + if (type->getBasicType()==Type::Class){ + if (arg->isConst()){ + mOutfile<<"const "; + } + mOutfile<getName(); + if (arg->isPointer()) + mOutfile<<"*"; + }else if (type->getBasicType()==Type::Integer){ + mOutfile<<"int"; + }else if (type->getBasicType()==Type::Enum){ + mOutfile<getName(); + }else if (type->getBasicType()==Type::String){ + if (!isReturn) + mOutfile<<"const std::string &"; + else + mOutfile<<"std::string"; + }else if (type->getBasicType()==Type::Void){ + mOutfile<<"void"; + }else if (type->getBasicType()==Type::Boolean){ + mOutfile<<"bool"; + } + if (!isReturn && !arg->getName().empty()) + mOutfile<<" "<getName(); +} + +void CplusplusGenerator::writeTabs(int ntabs){ + int i; + for(i=0;i100 && comment[i]==' ')){ + mOutfile<isCallback()) return; + + Argument *retarg=method->getReturnArg(); + const list &args=method->getArgs(); + list::const_iterator it; + + writeTabs(1); + mOutfile<<"/**"<getHelp(),1); + mOutfile<getName()<<"("; + + for(it=args.begin();it!=args.end();++it){ + if (it!=args.begin()) mOutfile<<", "; + writeArgument(*it); + } + mOutfile<<")"; + if (method->isConst()) mOutfile<<"const"; + mOutfile<<";"< classes=proj->getClasses(); + mCurProj=proj; +#ifndef WIN32 + remove(to_lower(proj->getName()).c_str()); + mkdir(to_lower(proj->getName()).c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH); +#else + _mkdir(to_lower(proj->getName()).c_str()); +#endif + ostringstream filename; + + /*write a file for the namespace*/ + filename<getName())<<"/"<getName())<<".js"; + mOutfile.open(filename.str().c_str()); + if (!mOutfile.is_open()){ + cerr<<"Could not write into "<getName()<getName()<<" = {};"<getName(); + if (strncasecmp(enum_name.c_str(),mCurProj->getName().c_str(),mCurProj->getName().size())==0){ + //since enum is part of the namespace, drop the namespace part of the enum if any. + enum_name.erase(0,mCurProj->getName().size()); + } + return enum_name; +} + +void JavascriptGenerator::writeEnum(Class *klass){ + if (klass->getType()!=Type::Enum) return; + + ostringstream filename; + list members=klass->getConstFields(); + list::iterator it; + string enum_name=getEnumName(klass); + int value=0; + + filename<getName())<<"/"<getName()<<" = "<getName()<<" || {};"<getHelp(),0); + mOutfile<getName()<<"."<getHelp().empty()){ + writeTabs(1); + mOutfile<<"/**"<getHelp(),1); + mOutfile<getName().substr(prefix_size,string::npos)<<" : "<getName() << ".get" << enum_name << "Text = function(value) {" << endl; + mOutfile << "\tswitch (value) {" << endl; + for (it = members.begin(); it != members.end(); it++) { + ConstField *cf = *it; + mOutfile << "\tcase " << mCurProj->getName() << "." << enum_name << "." << cf->getName().substr(prefix_size, string::npos) << ":" << endl; + mOutfile << "\t\treturn \"" << cf->getName().substr(prefix_size, string::npos) << "\";" << endl; + } + mOutfile << "\tdefault:" << endl; + mOutfile << "\t\treturn \"?\";" << endl; + mOutfile << "\t}" << endl; + mOutfile << "};" << endl; + + mOutfile.close(); +} + +void JavascriptGenerator::writeClass(Class *klass){ + ostringstream filename; + + if (klass->getType()==Type::Enum) { + return; + } + const list &methods=klass->getMethods(); + if (methods.empty()) return;//skip empty classes + + filename<getName())<<"/"<getName())<<".js"; + mOutfile.open(filename.str().c_str()); + if (!mOutfile.is_open()){ + cerr<<"Could not write into "<getName().empty()) + // mOutfile<<"namespace "<getName()<<"{"<getHelp()<getName()< properties=klass->getProperties(); + for_each(properties.begin(),properties.end(),bind1st(mem_fun(&JavascriptGenerator::writeProperty),this)); + mOutfile<getName().empty()) + // mOutfile<<"} //end of namespace "<getName()<getBasicType()){ + case Type::Float: + case Type::Integer: + mOutfile<<"number"; + break; + case Type::String: + mOutfile<<"string"; + break; + case Type::Boolean: + mOutfile<<"boolean"; + break; + case Type::Class: + mOutfile<<"external:"<getName(); + break; + case Type::Enum: + mOutfile<getName()<<"."<getClass(type->getName())); + break; + case Type::Void: + mOutfile<<"void"; + break; + case Type::Callback: + break; + case Type::Array: + mOutfile<<"Array."; + break; + } +} + +void JavascriptGenerator::writeArgument(Argument *arg, ArgKind kind){ + switch(kind){ + case Normal: + mOutfile<<" * @param {"; + writeType(arg->getType()); + mOutfile<<"} "<getName()<<" - "<getHelp()<getType()); + mOutfile<<"} "<getHelp()<getType()); + mOutfile<<"} "<getName()<<" - "<getHelp()<100 && comment[i]==' ')){ + mOutfile<getName()=="userData" || prop->getName()=="userPointer") return; + mOutfile<<"/**"<getHelp(),0); + mOutfile<getType()); + mOutfile<<"} external:"<getName()<<"#"<getName()<getAttribute()==Property::ReadOnly) + mOutfile<<" * @readonly"<getReturnArg(); + const list &args=method->getArgs(); + list::const_iterator it; + + if (method->isCallback()) return; + if (method->getPropertyBehaviour()!=Method::None) return; + if (method->getName()=="ref" || method->getName()=="unref") return; + + mOutfile<<"/**"<getHelp(),0); + mOutfile<getName()<<"#"<getName()< &args=event->getArgs(); + list::const_iterator it; + + if (!event->isCallback()) return; + mOutfile<<"/**"<getHelp()),0); + mOutfile<getName()<<"#"<getName()< + +#include "software-desc.hh" + +class OutputGenerator{ +public: + virtual void generate(Project *proj)=0; +}; + +class CplusplusGenerator : public OutputGenerator{ +public: + CplusplusGenerator(); + virtual void generate(Project *proj); +private: + void writeClass(Class *klass); + void writeArgument(Argument *arg, bool isReturn=false); + void writeTabs(int ntabs); + void writeHelpComment(const std::string &comment, int ntabs); + void writeMethod(Method *method); + void writeEnumMember(ConstField *cf, bool isLast); + ofstream mOutfile; + Project *mCurProj; + Class *mCurClass; +}; + +class JavascriptGenerator : public OutputGenerator{ +public: + JavascriptGenerator(); + virtual void generate(Project *proj); +private: + void writeClass(Class *klass); + void writeEnum(Class *klass); + void writeType(Type *type); + enum ArgKind { Normal, Return, PropertyArg}; + void writeArgument(Argument *arg, ArgKind kind=Normal); + void writeTabs(int ntabs); + void writeHelpComment(const std::string &comment, int ntabs); + void writeProperty(Property *prop); + void writeMethod(Method *method); + void writeEvent(Method *event); + string getEventHelp(const string &ref); + string getEnumName(Class *klass); + ofstream mOutfile; + Project *mCurProj; + Class *mCurClass; +}; + +string to_lower(const string &str); + +#endif diff --git a/tools/genwrappers.cc b/tools/genwrappers.cc new file mode 100644 index 000000000..a009a83d9 --- /dev/null +++ b/tools/genwrappers.cc @@ -0,0 +1,463 @@ +/* +linphone +Copyright (C) 2013 Belledonne Communications SARL +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 "software-desc.hh" +#include "generator.hh" + +#include +#include +#include +#include +#include +#include + + + +static bool isSpace(const char *str){ + for(;*str!='\0';++str){ + if (!isspace(*str)) return false; + } + return true; +} + +//Convenient class for examining node recursively +class XmlNode{ +public: + XmlNode(const xmlNode *node=NULL) : mNode(node){ + } + XmlNode getChild(const string &name)const{ + if (mNode==NULL) return XmlNode(); + xmlNode *it; + for(it=mNode->children;it!=NULL;it=it->next){ + if (xmlStrcmp(it->name,(const xmlChar*)name.c_str())==0) + return XmlNode(it); + } + return XmlNode(); + } + XmlNode getChildRecursive(const string &name)const{ + if (mNode==NULL) return XmlNode(); + xmlNode *it; + //find in direct children + for(it=mNode->children;it!=NULL;it=it->next){ + if (xmlStrcmp(it->name,(const xmlChar*)name.c_str())==0) + return XmlNode(it); + } + //recurse into children + for(it=mNode->children;it!=NULL;it=it->next){ + XmlNode res=XmlNode(it).getChildRecursive(name); + if (!res.isNull()) return res; + } + return XmlNode(); + } + list getChildren(const string &name)const{ + xmlNode *it; + list nodes; + + if (mNode==NULL) return nodes; + for(it=mNode->children;it!=NULL;it=it->next){ + if (xmlStrcmp(it->name,(const xmlChar*)name.c_str())==0) + nodes.push_back(XmlNode(it)); + } + if (nodes.empty()) cerr<<"getChildren() no "<content; + if (!isSpace(text)) return string(text); + } + return ""; + } + string getProp(const string &propname)const{ + if (mNode==NULL) return ""; + xmlChar *value; + value=xmlGetProp((xmlNode*)mNode,(const xmlChar*)propname.c_str()); + if (value) return string((const char*)value); + return ""; + } + bool isNull()const{ + return mNode==NULL; + } +private: + const xmlNode *mNode; +}; + +static Argument *parseArgument(XmlNode node, bool isReturn){ + string name=node.getChild("declname").getText(); + Type *type=NULL; + string typecontent=node.getChild("type").getText(); + bool isConst=false; + bool isPointer=false; + + //find documented type if any + string tname=node.getChild("type").getChild("ref").getText(); + if (!tname.empty()){ + type=Type::getType(tname); + }else type=Type::getType(typecontent); + + //find const attribute if any + if (typecontent.find("const")!=string::npos) + isConst=true; + + if (typecontent.find("*")!=string::npos) + isPointer=true; + + if (type==NULL) { + return NULL; + } + //cout<<"Parsed argument "<getBasicType()<<" "<getName()<0) + useUpper=true; + }else{ + if (useUpper) + *w++=toupper(p); + else + *w++=p; + useUpper=false; + } + } + *w++='\0'; + return tmp; +} + +static string extractMethodName(const string &c_name, const std::string& class_name){ + string prefix=classNameToPrefix(class_name); + if (c_name.find(prefix)==0){ + return makeMethodName(c_name.substr(prefix.size(),string::npos)); + } + return ""; +} + +static string getHelpBody(XmlNode myNode){ + ostringstream result; + XmlNode brief=myNode.getChild("briefdescription"); + XmlNode detailed=myNode.getChild("detaileddescription"); + + result< args; + string help; + XmlNode funcnode(node); + XmlNode parameterlist; + list params; + list paramsHelp; + list::iterator it,helpit; + + name=funcnode.getChild("name").getText(); + params=funcnode.getChildren("param"); + parameterlist=funcnode.getChild("detaileddescription").getChildRecursive("parameterlist"); + if (parameterlist.isNull()) cerr<<"parameterlist not found"<setHelp(item.getChild("parameterdescription").getChild("para").getText()); + }else cerr<<"Undocumented parameter "<getName()<<" in function "<getType()->getBasicType()!=Type::Class) return; + className=first_arg->getType()->getName(); + methodName=extractMethodName(name,className); + if (!methodName.empty() && methodName!="destroy"){ + //cout<<"Found "<isConst(),false); + method->setHelp(help); + proj->getClass(className)->addMethod(method); + delete first_arg; + } +} + +static string findCommon(const string &c1, const string & c2){ + size_t i; + ostringstream res; + for(i=0;i params=node.getChildRecursive("parameterlist").getChildren("parameteritem"); + list::iterator it=params.begin(); + string rettype=node.getChild("type").getText(); + argsstring=argsstring.substr(argsstring.find('(')+1,string::npos); + bool cont=true; + list args; + Type *firstArgType=NULL; + + rettype=rettype.substr(0,rettype.find('(')); + Argument *retarg=new Argument(Type::getType(rettype),"",false,rettype.find('*')!=string::npos); + + do{ + size_t comma=argsstring.find(','); + size_t end=argsstring.find(')'); + if (comma!=string::npos && commasetHelp((*it).getChild("parameterdescription").getChild("para").getText()); + ++it; + } + args.push_back(argobj); + }while(cont); + + if (firstArgType->getBasicType()!=Type::Class) return; + Class *klass=proj->getClass(firstArgType->getName()); + Method *callback=new Method("", retarg, extractCallbackName(name,klass->getName()), args, false, false, true); + //cout<<"Found callback "<getName()<<" with "<setHelp(node.getChild("detaileddescription").getChild("para").getText()); + klass->addMethod(callback); + + +} + +static void parseEnum(Project *proj, XmlNode node){ + string name=node.getChild("name").getText(); + if (name[0]=='_') name.erase(0,1); + Class *klass=proj->getClass(name); + klass->setHelp(node.getChild("detaileddescription").getChild("para").getText()); + list enumValues=node.getChildren("enumvalue"); + list::iterator it; + for (it=enumValues.begin();it!=enumValues.end();++it){ + ConstField *cf=new ConstField(Type::getType("int"),(*it).getChild("name").getText()); + cf->setHelp((*it).getChild("detaileddescription").getChild("para").getText()); + klass->addConstField(cf); + + } + +} + +static void parseTypedef(Project *proj, xmlNode *node){ + XmlNode tdef(node); + string typecontent=tdef.getChild("type").getText(); + string name=tdef.getChild("name").getText(); + if (typecontent.find("enum")==0){ + Type::addType(Type::Enum,name); + }else if (typecontent.find("(*")!=string::npos){ + parseCallback(proj,node); + }else + proj->getClass(name)->setHelp(getHelpBody(node)); +} + +static void parseMemberDef(Project *proj, xmlNode *node){ + XmlNode member(node); + string brief; + string detailed; + string kind; + + if (member.getChild("briefdescription").getText().empty() && + member.getChild("detaileddescription").getChild("para").getText().empty()) + return; + if (member.getProp("id").find("group__")!=0) + return; + if (member.getChild("detaileddescription").getChildRecursive("xreftitle").getText()=="Deprecated") + return; + + kind=member.getProp("kind"); + if (kind=="function"){ + parseFunction(proj,node); + }else if (kind=="typedef"){ + parseTypedef(proj,node); + }else if (kind=="enum"){ + parseEnum(proj,node); + } +} + +static void inspectNode(Project *proj, xmlNode *a_node){ + xmlNode *cur_node; + + for (cur_node = a_node; cur_node != NULL ; cur_node = cur_node->next) { + if (cur_node->type == XML_ELEMENT_NODE) { + //printf("node type: Element, name: %s\n", cur_node->name); + if (strcmp((const char*)cur_node->name,"memberdef")==0 ){ + //cout<<"Found memberdef"<children) inspectNode(proj,cur_node->children); + } +} + +static int parse_file(Project *proj, const char *filename){ + xmlDoc *doc = NULL; + xmlNode *root_element = NULL; + + + /*parse the file and get the DOM */ + doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER); + + if (doc == NULL) { + cerr<<"xmlReadFile failed."< files; + list::iterator it; + + LIBXML_TEST_VERSION + + for(i=1;i file1 file2...\nParses xml files generated by doxygen to output wrappers in a specified language.\n",argv[0]); + return -1; + }else if (strcmp(argv[i],"--output")==0){ + i++; + if (strcmp(argv[i],"c++")==0){ + gen=new CplusplusGenerator(); + }else if (strcmp(argv[i],"javascript")==0){ + gen=new JavascriptGenerator(); + } + }else if (strcmp(argv[i],"--project")==0){ + i++; + projectName=argv[i]; + }else{ + files.push_back(argv[i]); + } + } + + if (gen==NULL) { + cerr<<"No output generator selected !"<analyse(); + gen->generate(proj); + return 0; +} diff --git a/tools/lpc2xml.c b/tools/lpc2xml.c index 39fd62b0e..46a71a2b9 100644 --- a/tools/lpc2xml.c +++ b/tools/lpc2xml.c @@ -94,11 +94,11 @@ static void lpc2xml_genericxml_warning(void *ctx, const char *fmt, ...) { static int processEntry(const char *section, const char *entry, xmlNode *node, lpc2xml_context *ctx) { const char *content = lp_config_get_string(ctx->lpc, section, entry, NULL); - if(content == NULL) { - lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Issue when reading the lpc"); + if (content == NULL) { + lpc2xml_log(ctx, LPC2XML_ERROR, "Issue when reading the lpc"); return -1; } - + lpc2xml_log(ctx, LPC2XML_MESSAGE, "Set %s|%s = %s", section, entry, content); xmlNodeSetContent(node, (const xmlChar *) content); return 0; @@ -113,6 +113,13 @@ struct __processSectionCtx { static void processSection_cb(const char *entry, struct __processSectionCtx *ctx) { if(ctx->ret == 0) { + const char *comment = "#"; + if (strncmp(comment, entry, strlen(comment)) == 0) { + lpc2xml_log(ctx->ctx, LPC2XML_WARNING, "Skipped commented entry %s", entry); + ctx->ret = 0; + return; + } + xmlNode *node = xmlNewChild(ctx->node, NULL, (const xmlChar *)"entry", NULL); if(node == NULL) { lpc2xml_log(ctx->ctx, LPC2XML_ERROR, "Can't create \"entry\" element"); diff --git a/tools/lpc2xml_jni.cc b/tools/lpc2xml_jni.cc index c0971cbd5..c21ba7312 100644 --- a/tools/lpc2xml_jni.cc +++ b/tools/lpc2xml_jni.cc @@ -26,6 +26,7 @@ extern "C" { #endif #include +#include "mediastreamer2/mscommon.h" struct jni_lpc2xml_ctx { JNIEnv *env; @@ -52,10 +53,14 @@ extern "C" void Java_org_linphone_tools_Lpc2Xml_callback (void *ctx, lpc2xml_log char buffer[LPC2XML_CALLBACK_BUFFER_SIZE]; vsnprintf(buffer, LPC2XML_CALLBACK_BUFFER_SIZE, fmt, list); - jstring javaString = env->NewStringUTF(buffer); - jint javaLevel = level; - my_jni::callVoidMethod(env, obj, "Lpc2Xml", "printLog", "(ILjava/lang/String;)V", javaLevel, javaString); - } + + if (level == LPC2XML_ERROR) + ms_error("%s", buffer); + else if (level == LPC2XML_WARNING) + ms_warning("%s", buffer); + else + ms_message("%s", buffer); + } } extern "C" void Java_org_linphone_tools_Lpc2Xml_init(JNIEnv *env, jobject obj) { diff --git a/tools/my_jni.h b/tools/my_jni.h index ce56829ec..b02882ba3 100644 --- a/tools/my_jni.h +++ b/tools/my_jni.h @@ -35,7 +35,7 @@ static ReturnType call##Type##Method(JNIEnv *env, jobject obj, const char *class } \ jmethodID my_method = env->GetMethodID(my_class, methodName, methodSignature); \ if(my_method == 0) { \ - ms_error("Can't get %s %s %s method", className, methodSignature); \ + ms_error("Can't get %s %s %s method", className, methodName, methodSignature); \ return NULL; \ } \ va_list vl; \ diff --git a/tools/software-desc.cc b/tools/software-desc.cc new file mode 100644 index 000000000..7930cb289 --- /dev/null +++ b/tools/software-desc.cc @@ -0,0 +1,43 @@ +/* +linphone +Copyright (C) 2013 Belledonne Communications SARL +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 "software-desc.hh" + +Type Type::sStringType(Type::String); +Type Type::sIntegerType(Type::Integer); +Type Type::sVoidType(Type::Void); +Type Type::sBooleanType(Type::Boolean); +Type Type::sFloatType(Type::Float); +Type Type::sArrayType(Type::Array); + +std::map Type::mTypes; +const char *Type::sBasicTypeNames[]={ + "Void", + "Boolean", + "Integer", + "Float", + "String", + "Enum", + "Class", + "Callback", + "Array", + "undef", + "undef" +}; diff --git a/tools/software-desc.hh b/tools/software-desc.hh new file mode 100644 index 000000000..2d454e502 --- /dev/null +++ b/tools/software-desc.hh @@ -0,0 +1,470 @@ +/* +linphone +Copyright (C) 2013 Belledonne Communications SARL +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. +*/ + +#ifndef software_desc_hh +#define software_desc_hh + +#include +#include +#include +#include + +#include +#include +#include + + +using namespace::std; + + +class Type{ +public: + enum BasicType{ + Void, + Boolean, + Integer, + Float, + String, + Enum, + Class, + Callback, + Array + }; + static const char *sBasicTypeNames[]; + static Type* addType(BasicType bt, const string &name){ + Type* ret; + if ((ret=mTypes[name])==0){ + //cout<<"Adding new "<mBasic=bt; + } + return ret; + } + static Type *getType(const std::string &tname){ + if (tname.find("(")!=string::npos) return NULL; //arrives when parsing function pointer declared inside function prototype + if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){ + return &sStringType; + }else if (tname.find("int")!=string::npos){ + return &sIntegerType; + }else if (tname.find("size_t")!=string::npos){ + return &sIntegerType; + }else if (tname.find("float")!=string::npos){ + return &sFloatType; + }else if (tname.find("bool_t")!=string::npos){ + return &sBooleanType; + }else if (tname.find("void")!=string::npos){ + return &sVoidType; + }else if (tname.find("enum")!=string::npos){ + return addType(Enum,tname.c_str()+strlen("enum ")); + }else if (tname.find("MSList")!=string::npos){ + return &sArrayType; + }else{/*an object?*/ + + string tmp=tname; + size_t pos; + + /*really ugly and slow*/ + + pos=tmp.find('*'); + if (pos!=string::npos) + tmp.erase(pos,1); + + pos=tmp.find("const"); + if (pos!=string::npos) + tmp.erase(pos,strlen("const")); + + while ((pos=tmp.find(' '))!=string::npos){ + tmp.erase(pos,1); + } + return addType(Class,tmp); + } + cerr<<"Unhandled type name"< mTypes; +}; + + + +class Argument{ +public: + Argument(Type *type, const string &argname, bool isConst, bool isPointer) : mType(type), mName(argname), mConst(isConst), mPointer(isPointer){ + if (!isPointer) mConst=false; + } + Type *getType()const{ + return mType; + } + bool isConst()const{ + return mConst; + } + const string &getName()const{ + return mName; + } + bool isPointer()const{ + return mPointer; + } + const string &getHelp()const{ + return mHelp; + } + void setHelp(const string &help){ + mHelp=help; + } +private: + + Type *mType; + string mName; + string mHelp; + bool mConst; + bool mPointer; +}; + +class Method{ +public: + enum PropertyBehaviour{ + None, + Read, + Write + }; + Method(const std::string &uid, Argument* return_arg, const std::string &name, const list &args, bool isConst, bool isStatic, bool isCallback=false){ + mUid=uid; + mReturn=return_arg; + mName=name; + mArgs=args; + mConst=isConst; + mStatic=isStatic; + mIsCallback=isCallback; + analyseProperties(); + } + void setHelp(const std::string &help){ + mHelp=help; + } + Argument *getReturnArg()const{ + return mReturn; + } + const string &getName()const{ + return mName; + } + const list &getArgs()const { + return mArgs; + } + bool isConst()const{ + return mConst; + } + bool isStatic()const{ + return mStatic; + } + bool isCallback()const{ + return mIsCallback; + } + const string &getHelp(){ + return mHelp; + } + PropertyBehaviour getPropertyBehaviour()const{ + return mPropertyBehaviour; + } + const string &getPropertyName()const{ + return mPropertyName; + } +private: + void analyseProperties(){ + size_t enabled_pos; + mPropertyBehaviour=None; + + if (mName.find("get")==0 && mArgs.size()==0){ + mPropertyName=mName.substr(3,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Read; + } + }else if (mName.find("is")==0 && mArgs.size()==0){ + mPropertyName=mName.substr(2,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Read; + } + }else if (mName.find("enable")==0 && mArgs.size()==1){ + mPropertyName=mName.substr(6,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyName+="Enabled"; + mPropertyBehaviour=Write; + } + }else if (mName.find("set")==0 && mArgs.size()==1){ + mPropertyName=mName.substr(3,string::npos); + if (!mPropertyName.empty()){ + mPropertyName[0]=tolower(mPropertyName[0]); + mPropertyBehaviour=Write; + } + }else if ((enabled_pos=mName.rfind("Enabled"))!=string::npos && mArgs.size()==0){ + size_t goodpos=mName.size()-7; + if (enabled_pos==goodpos){ + mPropertyName=mName.substr(0,goodpos); + if (!mPropertyName.empty()){ + mPropertyName+="Enabled"; + mPropertyBehaviour=Read; + } + } + } + if (mPropertyBehaviour==None) { + mPropertyName=""; + if (mName.find("create")==0) { + mName="new"+mName.substr(6,string::npos); + } + } + } + string mUid; + Argument *mReturn; + string mName; + list mArgs; + string mHelp; + string mPropertyName; /*if it can be a property*/ + PropertyBehaviour mPropertyBehaviour; + bool mConst; + bool mStatic; + bool mIsCallback; +}; + +class Property{ +public: + enum Attribute{ + ReadOnly, + ReadWrite + }; + Property(Attribute attr, const string &name, Type *type, const string &help) : mAttr(attr), mName(name), mType(type), mHelp(help){ + } + const string &getName()const{ + return mName; + } + const string &getHelp()const{ + return mHelp; + } + void setHelp(const string &help){ + mHelp=help; + } + Attribute getAttribute()const{ + return mAttr; + } + void setAttribute(Attribute attr){ + mAttr=attr; + } + Type* getType()const{ + return mType; + } +private: + Attribute mAttr; + string mName; + Type *mType; + string mHelp; +}; + +class ConstField{ +public: + ConstField(Type *type, const string &name, const string &value="") : mType(type), mName(name), mValue(value){ + } + void setHelp(const string & help){ + mHelp=help; + } + const string &getHelp()const{ + return mHelp; + } + const string & getName()const{ + return mName; + } + Type *getType()const{ + return mType; + } + const string &getValue()const{ + return mValue; + } + static string getCommonPrefix(list fields){ + if (fields.size()<2) return ""; + list::iterator it; + string prefix=fields.front()->getName(); + int prefixsize; + + for (prefixsize=prefix.size();prefixsize>0;prefixsize--){ + bool isMatching=true; + prefix=prefix.substr(0,prefixsize); + + for(it=fields.begin();it!=fields.end();++it){ + ConstField *cf=*it; + if (prefix != cf->getName().substr(0,prefixsize)){ + isMatching=false; + break; + } + } + if (isMatching){ + //cout<<"enum prefix: "< +struct name_matcher{ + name_matcher(const string &name) : mName(name){} + bool operator()(_type *cf){ + return cf->getName()==mName; + } + string mName; +}; + +/*actually a class or an enum*/ +class Class{ +public: + Class(const std::string &name): mName(name){ + } + Type::BasicType getType(){ + return Type::getType(mName)->getBasicType(); + } + void addMethod(Method *method){ + if (mMethods.find(method->getName())==mMethods.end()) + mMethods.insert(make_pair(method->getName(),method)); + } + void addConstField(ConstField *field){ + list::iterator it=find_if(mConstFields.begin(),mConstFields.end(),name_matcher(field->getName())); + if (it==mConstFields.end()) + mConstFields.push_back(field); + } + void setHelp(const std::string &help){ + mHelp=help; + } + list getMethods()const{ + list ret; + map::const_iterator it; + for(it=mMethods.begin();it!=mMethods.end();++it){ + ret.push_back((*it).second); + } + return ret; + } + const list &getConstFields()const{ + return mConstFields; + } + const string &getName()const{ + return mName; + } + const string &getHelp()const{ + return mHelp; + } + list getProperties(){ + list ret; + map::const_iterator it; + for(it=mProperties.begin();it!=mProperties.end();++it){ + ret.push_back((*it).second); + } + return ret; + } + void computeProperties(){ + map::const_iterator it; + Property *prop; + for (it=mMethods.begin();it!=mMethods.end();++it){ + Method *m=(*it).second; + if (m->getPropertyBehaviour()==Method::Read){ + prop=mProperties[m->getPropertyName()]; + if (prop==NULL){ + prop=new Property(Property::ReadOnly,m->getPropertyName(),m->getReturnArg()->getType(), m->getHelp()); + mProperties[m->getPropertyName()]=prop; + } + }else if (m->getPropertyBehaviour()==Method::Write){ + prop=mProperties[m->getPropertyName()]; + if (prop==NULL){ + prop=new Property(Property::ReadWrite,m->getPropertyName(),m->getArgs().front()->getType(), m->getHelp()); + mProperties[m->getPropertyName()]=prop; + }else{ + prop->setHelp(m->getHelp()); + prop->setAttribute(Property::ReadWrite); + } + } + } + } +private: + map mMethods; + map mProperties; + list mConstFields; + string mName; + string mHelp; +}; + +class Project{ +public: + Project(const string &name="wrapper") : mName(name){ + } + Class *getClass(const std::string &name){ + Class *ret; + if ((ret=mClasses[name])==NULL){ + ret=mClasses[name]=new Class(name); + } + return ret; + } + list getClasses()const{ + list ret; + map::const_iterator it; + for(it=mClasses.begin();it!=mClasses.end();++it){ + ret.push_back((*it).second); + } + return ret; + } + const string &getName()const{ + return mName; + } + void analyse(){ + list classes=getClasses(); + for_each(classes.begin(),classes.end(),mem_fun(&Class::computeProperties)); + } + void addCallback(Method *callback){ + list::iterator it=find_if(mCallbacks.begin(),mCallbacks.end(),name_matcher(callback->getName())); + if (it==mCallbacks.end()) + mCallbacks.push_back(callback); + } + const list &getCallbacks()const{ + return mCallbacks; + } +private: + map mClasses; + list mCallbacks; + string mName; +}; + +#endif diff --git a/tools/xml2lpc.c b/tools/xml2lpc.c index c9a5c94e2..d02133674 100644 --- a/tools/xml2lpc.c +++ b/tools/xml2lpc.c @@ -114,15 +114,18 @@ static void dumpNodes(int level, xmlNode * a_node, xml2lpc_context *ctx) { static void dumpNode(xmlNode *node, xml2lpc_context *ctx) { - xml2lpc_log(ctx, XML2LPC_DEBUG, "node type: %d, name: %s", node->type, node->name); + xml2lpc_log(ctx, XML2LPC_DEBUG, "node type: %d, name: %s", node->type, node->name); } static void dumpAttr(xmlNode *node, xml2lpc_context *ctx) { - xml2lpc_log(ctx, XML2LPC_DEBUG, "attr name: %s value:%s", node->name, node->children->content); + xml2lpc_log(ctx, XML2LPC_DEBUG, "attr name: %s value:%s", node->name, node->children->content); } static void dumpContent(xmlNode *node, xml2lpc_context *ctx) { - xml2lpc_log(ctx, XML2LPC_DEBUG, "content: %s", node->children->content); + if (node->children) + xml2lpc_log(ctx, XML2LPC_DEBUG, "content: %s", node->children->content); + else + xml2lpc_log(ctx, XML2LPC_DEBUG, "content: "); } static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_context *ctx) { @@ -142,8 +145,11 @@ static int processEntry(xmlElement *element, const char *sectionName, xml2lpc_co } } - value = (const char *)element->children->content; dumpContent((xmlNode *)element, ctx); + if (element->children) + value = (const char *)element->children->content; + else + value = ""; if(name != NULL) { const char *str = lp_config_get_string(ctx->lpc, sectionName, name, NULL); diff --git a/tools/xml2lpc_jni.cc b/tools/xml2lpc_jni.cc index fd72c6895..a242e7ce8 100644 --- a/tools/xml2lpc_jni.cc +++ b/tools/xml2lpc_jni.cc @@ -26,6 +26,7 @@ extern "C" { #endif #include +#include "mediastreamer2/mscommon.h" struct jni_xml2lpc_ctx { JNIEnv *env; @@ -52,9 +53,13 @@ extern "C" void Java_org_linphone_tools_Xml2Lpc_callback (void *ctx, xml2lpc_log char buffer[XML2LPC_CALLBACK_BUFFER_SIZE]; vsnprintf(buffer, XML2LPC_CALLBACK_BUFFER_SIZE, fmt, list); - jstring javaString = env->NewStringUTF(buffer); - jint javaLevel = level; - my_jni::callVoidMethod(env, obj, "Xml2Lpc", "printLog", "(ILjava/lang/String;)V", javaLevel, javaString); + + if (level == XML2LPC_ERROR) + ms_error("%s", buffer); + else if (level == XML2LPC_WARNING) + ms_warning("%s", buffer); + else + ms_message("%s", buffer); } }